乐趣区

关于java:23种设计模式Java版第五篇

ps:本文系转载文章,浏览原文可获取源码,文章开端有原文链接

ps:这一篇是写策略模式、办法模板模式和观察者模式

1、策略模式

定义了一系列算法,把每个算法的外部实现细节都暗藏起来,并且它们之间能够互相取代,同时算法的扭转不会影响到客户端。

策略模式有以下几种角色:

(1)形象策略类:定义了一个公共接口,具体策略类以不同的形式实现这个接口。

(2)具体策略类:实现了形象策略的接口,实现了具体的算法。

(3)环境类:它的属性含有一个形象策略类的援用,提供给客户端应用。

这里举个例子,假如买某一件商品,原件超过 700 块钱的就打 8 折,原价超过 850 块钱的就打 85 折,咱们用代码实现一下:

(1)形象策略类,新建一个 Price 接口:

public interface Price {

public double getPrice(double s);

}

(2)具体策略类,新建一个 Price8 类并实现 Price 接口:

public class Price8 implements Price{

@Override
public double getPrice(double s) {

System.out.println("打 8 折");
return 0.8*s;

}

}

(3)具体策略类,新建一个 Price85 类并实现 Price 接口:

public class Price85 implements Price{

@Override
public double getPrice(double s) {

System.out.println("打 85 折");
return 0.85*s;

}

}

(4)环境类,新建一个 Context 类:

public class Context {

private Price price;
public Context(Price price) {setPrice(price);
}
public void printPrice(double s) {System.out.println("原价为:" + s);
  System.out.println("打折后的价格为:" + price.getPrice(s));
}

public void setPrice(Price price) {this.price = price;}

}

客户端进行测试调用:

   Context cxt = new Context(new Price85());
   cxt.printPrice(996);
   
   cxt.setPrice(new Price8());
   cxt.printPrice(800);

日志打印如下所示:

图片

当客户端晓得具体的策略规定之后,尽管环境类持有形象策略类的援用,然而在客户端这里传入具体的策略类对象给环境类同时并把相应的原价传给环境类的 printPrice 办法;原件超过 700 块钱的就打 8 折是一个策略,原价超过 850 块钱的就打 85 折是另外一个策略。

应用策略模式避免出现多层条件语句,它的新算法灵便,新增加具体策略类的同时,不须要改原代码,只须要把具体策略类对象传递给环境类对象相应的办法;算法的具体实现放在具体策略类中,而算法的调用是放在环境类中,具体策略类和环境类进行了拆散;然而客户端须要晓得所有具体策略算法的不同,能力更好的抉择适宜的具体策略类;策略模式制作很多具体的策略类,保护复杂度逐步减少。

2、办法模板模式

定义一个操作流程中的算法框架,将算法的一些步骤延长到子类中,让子类不扭转该算法构造的条件下再次定义该算法的某些特定步骤。

办法模板模式有以下角色:

(1)抽象类:定义了算法的框架, 依照开发者指定顺序调用根本办法。

根本办法蕴含如下所示:

形象办法:在抽象类中进行定义,由子类本人去实现。

具体方法:在抽象类中曾经实现,由子类中间接应用或重写它。

钩子办法:在抽象类中曾经实现,包含用于判断的逻辑办法和须要子类重写的空办法两种;比如说有一个接口或者一个抽象类 A,这个接口或者抽象类 A 里有 N(N 大于 1)个办法,咱们只想用其中一个办法,咱们能够写一个抽象类 B 实现这个接口或者继承抽象类 A,在这个抽象类 B 里将你要用的那个办法设置为 abstract method,其它办法进行空实现,而后咱们再写一个子类 C 继承这个抽象类 B,就不须要实现其它不必的办法,只须要实现 abstract method 办法,abstract method 办法就是钩子办法。

(2)具体实现类:实现抽象类中或者接口中所申明的形象办法和钩子办法,它们是模板办法中逻辑组成部分。

上面咱们举个例子,例如,去银行办理业务个别要通过以下 3 个流程:取号、办理具体业务(取钱、理财等)、对银行工作人员进行评分等;咱们用代码模仿一下:

(1)抽象类,写一个抽象类 Father:

public abstract class Father {

public void a(){System.out.println("排队取号");
}
public void c() {System.out.println("给工作人员评分");
}
public abstract void b();
public void d() {this.a();
  this.b();
  this.c();}

}

(2)具体实现类,写一个 SonA 类并继承 Father:

class SonA extends Father {

@Override
public void b() {

System.out.println("我要取钱");

}

}

(3)具体实现类,写一个 SonB 类并继承 Father:

class SonB extends Father {

@Override
public void b() {

System.out.println("我要理财");

}

}

(4)在客户端进行测试调用:

    Father f = new SonA();
    f.d();
    System.out.println("--------------------");
    Father f2 = new SonB();
    f2.d();

日志打印如下所示:

图片

抽象类 Father 提供了模板办法 d 并把 a、b 和 c 这 3 个办法依照程序进行调用,其中 a 和 c 办法曾经是固定好了的,而 b 办法是具体的业务,每个 Father 子类具体的业务不一样,所以 b 办法由子类去实现并调用模板办法 d。

尽管办法模板模式封装了抽象类或者接口不变局部办法并提取了公共一些代码,扩大可变局部,把可变局部拓展到子类中去实现;然而对每个不同的业务都要新增加一个子类并继承领有办法模板的父类,这会导致类的个数减少,设计更加形象,同时继承的关系也会带来肯定的局限性,父类每增加一个形象办法,所有子类都要增加一个实现办法。

3、观察者模式

多个对象之间存在一对多的依赖关系,当一个被依赖的对象的状态产生扭转时,依赖它的所有对象都会被告诉并立刻更新。

(1)形象被观察者角色:提供用于保留被观察者对象的汇集类和减少、删除被观察者对象的办法和告诉所有被观察者的办法。

(2)具体被观察者角色:它实现形象被观察者角色的办法,在被观察者外部状态扭转时,告诉所有注册过的观察者对象。

(3)形象观察者角色:它是一个抽象类或接口,申明一个当接到具体的更改告诉时被调用的办法。

(4)具体观察者角色:实现形象观察者中定义的形象办法,该办法接管到告诉时更新本身的状态。

上面咱们用代码举个具体的例子:

(1)形象被观察者角色,写一个 ISend 接口:

public interface ISend {
public void register(Reciever reciever);
public void notifiAll(int i);
public void setState(int state);
public int getSate();
}

(2)具体被观察者角色,写一个 Send 类并实现 ISend 接口:

public class Send implements ISend{

private int state = 0;
private List<Reciever> list = new ArrayList<Reciever>();
@Override
public void setState(int state) {this.state = state;}
@Override
public int getSate() {return this.state;}
@Override
public void register(Reciever reciever) {list.add(reciever);
}
@Override
public void notifiAll(int i) {for (Reciever reciever:list) {reciever.update(i);
  }
}

}

(3)形象观察者角色,写一个 Reciever 接口:

public interface Reciever {

public void update(int i);

}

(4)具体观察者角色,写一个 ReceiverA 类并实现 Reciever 接口:

class ReceiverA implements Reciever {
private int state = 0;
private String nameString;
public ReceiverA(String name) {

this.nameString = name;

}
@Override
public void update(int i) {

state = i;

}
public int getState() {

return this.state;

}
@Override
public String toString() {

// TODO 主动生成的办法存根
return nameString + "----------" + state;

}

}

(5)具体观察者角色,写一个 ReceiverB 类并实现 Reciever 接口:

class ReceiverB implements Reciever {
private int state = 0;
private String nameString;
public ReceiverB(String name) {

this.nameString = name;

}
@Override
public void update(int i) {

state = i;

}
public int getState() {

return this.state;

}
@Override
public String toString() {

// TODO 主动生成的办法存根
return nameString + "----------" + state;

}

}

(6)具体观察者角色,写一个 ReceiverC 类并实现 Reciever 接口:

class ReceiverC implements Reciever {
private int state = 0;
private String nameString;
public ReceiverC(String name) {

this.nameString = name;

}
@Override
public void update(int i) {

state = i;

}
public int getState() {

return this.state;

}
@Override
public String toString() {

// TODO 主动生成的办法存根
return nameString + "----------" + state;

}

}

(7)客户端进行测试调用:

    ISend send = new Send();
    Reciever recieverA = new ReceiverA("A");
    Reciever recieverB = new ReceiverB("B");
    Reciever recieverC = new ReceiverC("C");
    send.register(recieverA);
    send.register(recieverC);
    send.register(recieverB);
    send.setState(999);
    send.notifiAll(send.getSate());
    System.out.println(recieverA);
    System.out.println(recieverB);
    System.out.println(recieverC);

日志打印如下所示:

图片

一开始 ReceiverA、ReceiverB 和 ReceiverC 的属性 state 为 0,并对 send 进行注册,这样 send 和 ReceiverA、ReceiverB、ReceiverC 造成一对多的依赖关系,send 的 state 的属性值产生扭转时,会告诉 ReceiverA、ReceiverB 和 ReceiverC 的 state 属性值产生扭转。

观察者模式尽管升高了被观察者与观察者之间的耦合性,建设了一对多的依赖关系;然而它们之间的依赖关系不能齐全解除,很有可能呈现互相援用的状况。

退出移动版