具体的设计模式(三):行为型模式

行为型模式:

有11种:策略模式,模板方法,观察者模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式。

先来张图,看看这11中模式的关系:

第一类:通过父类与子类的关系进行实现。第二类:两个类之间。第三类:类的状态。第四类:通过中间类。

这里写图片描述


13.策略模式(Strategy)

简单说明:定义一系列的算法,把它们一个个封装起来,并且使他们可相互替换。

应用实例:

  1. 诸葛亮的锦囊妙计,每一个锦囊就是一个策略
  2. 旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略

举例说明:

设计一个策略的接口

package strategy;

/**
 * 策略模式: 一个类的行为或其算法可以在运行时更改。行为类设计模式
 * 设计一个接口,然后写不同的策略实现类,这些实现类,实现同一接口
 * 意图:定义一系列的算法,把他们一个一个封装起来,并且使它们可相互替换
 * 在多种算法相似的情况下,使用if...else所带来的复杂和难以维护。
 * 
 * 应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 
 *        2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。
 *        3、JAVA AWT 中的 LayoutManager。
 * @author cx
 * 优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
         缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
 */

public interface Strategy {

    public int doOperation(int num1,int num2);
}

加法策略

package strategy;

public class OperationAdd implements Strategy{

    //实现加法
    @Override
    public int doOperation(int num1, int num2) {
        // TODO 自动生成的方法存根
        return num1+num2;
    }

}

减法策略

package strategy;

public class OperationSubstract implements Strategy{

    //实现减法
    @Override
    public int doOperation(int num1, int num2) {
        // TODO 自动生成的方法存根
        return num1-num2;
    }

}

乘法策略

package strategy;

public class OperationMultiply implements Strategy{

    @Override
    public int doOperation(int num1, int num2) {
        // TODO 自动生成的方法存根
        return num1*num2;
    }

}

除法策略

package strategy;

public class OperationDivision implements Strategy{

    //除法
    @Override
    public int doOperation(int num1, int num2) {
        // TODO 自动生成的方法存根
        return num1/num2;
    }

}

执行策略的类

package strategy;

public class Context {

    private Strategy strategy;

    public Context(Strategy strategy){
        this.strategy=strategy;
    }

    public int executeStrategy(int num1,int num2){
        return strategy.doOperation(num1,num2);
    }
}

测试Test

package strategy;

public class Test {

    public static void main(String[] args) {
        int num1=10,num2=5;

        Context context=new Context(new OperationAdd());
        System.out.println("10+5="+context.executeStrategy(num1, num2));

        context=new Context(new OperationSubstract());
        System.out.println("10-5="+context.executeStrategy(num1, num2));

        context=new Context(new OperationMultiply());
        System.out.println("10*5="+context.executeStrategy(num1, num2));

        context=new Context(new OperationDivision());
        System.out.println("10/5="+context.executeStrategy(num1, num2));
    }
}

测试结果

10+5=15
10-5=5
10*5=50
10/5=2

14.模板方法(Template)

简单说明:一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。

意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

举例说明:

设计一个Game抽象类模板,并定义了一些抽象方法,和一些非抽象方法(在非抽象方法中,定义了抽象方法的执行顺序)

package template;

/**
 * 模板模式:一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需求重写方法实现。
 * @author cx
 * 意图:定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构
 *      即可重新定义该算法的某些特定步骤。
 * 关键:在抽象类中定义一个final的具体方法,用来归束抽象类中抽象方法的执行结构(顺序).
 *     然后在子类中,让其自动生成抽象类中定义的那些模板方法
 * 
 * 优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
         缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

         使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
         注意事项:为防止恶意操作,一般模板方法都加上 final 关键词。
 */


public abstract class Game {

    abstract void initialize();

    abstract void startPlay();

    abstract void endPlay();

    //模板方法为final,不可重写
    public final void play(){

        //初始化游戏
        initialize();

        //开始游戏
        startPlay();

        //结束游戏
        endPlay();
    }
}

BasketballGame 子类继承了Game抽象类,并实现了其抽象方法

package template;

public class BasketballGame extends Game{

    @Override
    void initialize() {
        // TODO 自动生成的方法存根
        System.out.println("basketball initialize...");
    }

    @Override
    void startPlay() {
        // TODO 自动生成的方法存根
        System.out.println("basketball startplay...");
    }

    @Override
    void endPlay() {
        // TODO 自动生成的方法存根
        System.out.println("basketball endplay...");
    }

}

FootballGame 子类继承了Game抽象类,并实现了其抽象方法

package template;

public class FootballGame extends Game{

    @Override
    void initialize() {
        // TODO 自动生成的方法存根
        System.out.println("football initalize...");
    }

    @Override
    void startPlay() {
        // TODO 自动生成的方法存根
        System.out.println("football startplay...");
    }

    @Override
    void endPlay() {
        // TODO 自动生成的方法存根
        System.out.println("football endplay...");
    }

}

测试(Test)

package template;

public class Test {
    public static void main(String[] args) {

        Game game=new FootballGame();
        game.play();
        System.out.println("--------------------");
        game=new BasketballGame();
        game.play();
    }
}

测试结果

football initalize...
football startplay...
football endplay...
--------------------
basketball initialize...
basketball startplay...
basketball endplay...

15.观察者模式(Observer)

简单说明:当一个对象被修改时,则会通知它的依赖对象,并且所有依赖它的对象都得到通知并被自动更新。

实例说明:RxJava 中用到了观察者模式,EventBus中也用到了观察者模式。

举例说明:

设计一个观察者接口

package observer;

/**
 * 观察者模式(Observer):当一个对象变化时,其他依赖该对象的对象都会收到通知,并且随着变化
 * 对象之间是一种一对多的关系
 * @author cx
 * 意图:定义对象间的一种一对多的依赖关系,当一个对象的状态改变时,所有依赖于它的对象都得到通知并被自动更新.
 * 关键:在AbstractSubscribe中有一个ArrayList存放的观察者们
 * 
 * 应用实例:拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价
 * 
 * 
 *  优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
    缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
         2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
    使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
    注意事项: 1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 
           3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
 */
public interface Observer {

    public void update();
}

Observer1 观察子接口1

package observer;


public class Observer1 implements Observer{

    @Override
    public void update() {
        // TODO 自动生成的方法存根
        System.out.println("Observer1 has received!");
    }

}

Observer2观察子接口2

package observer;

public class Observer2 implements Observer{

    @Override
    public void update() {
        // TODO 自动生成的方法存根
        System.out.println("Observer2 has received!");
    }

}

订阅者(包含所有对观察者的操作)

package observer;

//订阅者

public interface Subscribe {

    //增加观察者
    public void add(Observer observer);

    //删除观察者
    public void del(Observer observer);

    //通知所有的观察者
    public void notifyObservers();

    //自身的操作
    public void operation();
}

抽象类AbstractSubscribe实现Subscribe接口,并加入集合ArrayList来存取Observer对象

package observer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

public abstract class AbstractSubscribe implements Subscribe{

    private List<Observer> list=new ArrayList<Observer>();

    @Override
    public void add(Observer observer) {
        // TODO 自动生成的方法存根
        list.add(observer);
    }

    @Override
    public void del(Observer observer) {
        // TODO 自动生成的方法存根
        list.remove(observer);
    }

    @Override
    public void notifyObservers() {
        // 用迭代器遍历 List集合中所有的Observer对象
        Iterator<Observer> iterator=list.iterator();
        while(iterator.hasNext()){
            iterator.next().update(); //更新所有Observer对象
        }

/*      也可采用增强for循环来遍历所有的Observer对象
 *      for(Observer observer:list){
            observer.update();
        }*/

    }

    //抽象方法(一定实现的操作)
    public abstract void operation();
}

实现AbstractSubscribe抽象类的抽象方法

package observer;

public class MySubscribe extends AbstractSubscribe{

    @Override
    public void operation() {
        // TODO 自动生成的方法存根
        System.out.println("update self!");
        notifyObservers();
    }
}

测试类(Test)

package observer;

/**
 * MySubscribe类就是我们的主对象,Observer1和Observer2是依赖于MySubscribe的对象,
 * 当MySubscribe变化时,这两个对象必然变化。
 * AbstractSubscribe类中定义着需要监控的对象列表,可以对其进行修改:增加或删除被监控对象,
 * 当MySubscribe变化时,负责通知在列表内存在的对象
 * 
 * @author cx
 *
 */
public class Test {

    public static void main(String[] args) {
        Subscribe subscribe=new MySubscribe();

        subscribe.add(new Observer1());  //添加Observer对象  
        subscribe.add(new Observer2()); 

        subscribe.operation();  //subscribe 发出消息,所有Observer会做出响应
    }
}

测试结果

update self!
Observer1 has received!
Observer2 has received!

16.迭代子模式(Iterator)

简单说明:这种模式用于顺序访问集合对象的各个元素,而不需要知道集合对象的底层表示。

应用实例:JAVA中的iterator

举例说明:

泛型接口

package iterator;

public interface MyIterable<T>{

    MyIterator<T> iterator();
}

迭代器接口

package iterator;

/**
 * 迭代器模式:
 * 意图:提供一种方法顺序访问一个聚合对象中各个元素,而又无需暴露该对象的内部表示
 *      这种模式用于顺序访问集合对象中的元素,不需要知道集合对象的底层表示
 * 
 * 使用:遍历一个聚合对象
 * 优点:   1、它支持以不同的方式遍历一个聚合对象。
 *      2、迭代器简化了聚合类。 3、在同一个聚合上可以有多个遍历。
 *      4、在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。
         缺点:        由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,
            类的个数成对增加,这在一定程度上增加了系统的复杂性。
 * @author cx
 *
 * @param <E>
 */

public interface MyIterator<E>{

    //前移
    public Object previous();

    //后移
    public Object next();

    //是否有下一个元素
    public boolean hasNext();

    //取得第一个元素
    public Object first();
}

自定义集合接口,这里为了区分JAVA JDK中的集合类,特意取了别名MyColleation

package iterator;

public interface MyCollection<E> extends MyIterable<E>{

    //集合中写一个未实现的方法(关于MyIterator迭代器的)
    public MyIterator<E> iterator();

    //取得集合元素
    public Object get(int i);

    //取得集合大小
    public int size();

    //添加集合元素
    public Object add(String string);

}

实现集合类中的操作

package iterator;

public class MyCollectionImpl<E> implements MyCollection<E>{

    private int size=10;//预留数组大小,可以通过扩容数组来实现
    public String str[]=new String[size];

    private int i=0;
    @Override
    public Object get(int i) {
        // TODO 自动生成的方法存根
        return str[i];
    }

    @Override
    public int size() {
        // TODO 自动生成的方法存根
        return str.length;
    }

    @Override
    public MyIterator<E> iterator() {
        // TODO 自动生成的方法存根
        return new MyIteratorImpl(this);
    }

    @Override
    public Object add(String string) {
        // TODO 自动生成的方法存根

        if(i<size){
            str[i]=string;
            i++;
        }else{
            String[] temp=new String[size];
            for(int j=0;j<size;j++){
                temp[j]=str[j];
            }
            str=new String[size*2];
            for(int j=0;j<size;j++){
                str[j]=temp[j];
            }
            str[i]=string;
            i++;
        }

        return str;

    }

}

迭代器接口的实现类,同样为了区分JAVA JDK 中的 Iterator接口名 特意取名MyIterator

package iterator;

public class MyIteratorImpl implements MyIterator{

    private MyCollection myCollection;
    private int pos=-1;


    public MyIteratorImpl(MyCollection myCollection) {
        this.myCollection=myCollection;
    }

    @Override
    public Object previous() {
        //获取上一个元素
        if(pos>0){
            pos--;
        }
        return myCollection.get(pos);
    }

    @Override
    public Object next() {
        //获取下一个元素
        if(pos<myCollection.size()-1){
            pos++;
        }
        return myCollection.get(pos);
    }

    @Override
    public boolean hasNext() {
        //是否有下一个元素
        if(pos<myCollection.size()-1){
            return true;
        }else{
            return false;
        }
    }

    @Override
    public Object first() {
        //返回第一个元素
        pos=0;
        return myCollection.get(pos);
    }

}

测试(Test)

package iterator;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        MyCollectionImpl myCollectionImpl=new MyCollectionImpl();
        MyCollection<String> impl=new MyCollectionImpl<>();
        impl.add("1");
        impl.add("2");
        impl.add("3");
        impl.add("4");
        impl.add("5");
        impl.add("6");
        impl.add("7");
        impl.add("8");
        impl.add("9");
        impl.add("10");


        MyIterator<String> iterator2=impl.iterator();
        while(iterator2.hasNext()){
            System.out.print(" "+iterator2.next());
        }

    }
}

测试结果

 1 2 3 4 5 6 7 8 9 10

17.责任链模式(ResponsibilityChain)

简单说明:该模式为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。

意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,
将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

举例说明:

package responsibilitychain;

public interface Handler {

    //操作
    public void operator();
}
package responsibilitychain;

public abstract class AbstractHandler {

    private Handler handler;

    public Handler getHandler() {
        return handler;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

}
package responsibilitychain;

/**
 * 责任链模式:   有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递
 *          直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以
 *          责任链模式可以实现。
 * 
 * 强调一点就是:链接上的请求可以是一条链,模式本身不约束这个,需要我们自己去实现。
 *          同时,在一个时刻,命令只允许由一个对象传给另一个对象,而不允许传给多个对象。
 * @author cx
 *
 */

public class MyHandler extends AbstractHandler implements Handler{

    private String name;

    public MyHandler(String name) {
        this.name=name;
    }


    @Override
    public void operator() {
        System.out.println(name+"deal!");
        if(getHandler()!=null){
            getHandler().operator();      //递归调用operator()
        }
    }

}
package responsibilitychain;

public class Test {

    public static void main(String[] args) {
        MyHandler h1=new MyHandler("h1");
        MyHandler h2=new MyHandler("h2");
        MyHandler h3=new MyHandler("h3");

        h1.setHandler(h2);  //将h1对象和h2对象和h3对象进行关联引用
        h2.setHandler(h3);  //链式调用
        h1.operator();      //操作将这些绑定在一条链中,一个一个调用
    }
}

测试结果

h1deal!
h2deal!
h3deal!

18.命令模式(Command)

简单说明:请求以命令的形式包裹在对象中,并传给调用对象。将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化。

举例说明:

package command;

/**
 * 命令模式:很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,
 *           口令经过传递,传到了士兵耳朵里,士兵去执行。三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己
 *         的事儿就行,司令员要的是结果,不会去关注到士兵去实现的。
 * 
 *  Invoker 是调用者(司令员),Receiver 是被调用者(士兵),MyCommand 是命令,持有接收对象
 * @author cx
 *
 * 命令模式的目的就是达到命令的发出者和执行者解耦,实现请求和执行分开,Struts其实就是一种将请求和呈现分离的技术
 */
public interface Command {

    //命令者发布的命令类


    //执行这个命令的方法(交给接受者)
    public void exec();
}

接收者类(士兵)

package command;

/**
 * 接收命令者:(士兵)
 * @author cx
 *
 */
public class Receiver {

    public void action(){
        //接收命令的人执行命令的方法
        System.out.println("Command received!");
    }
}

命令类

package command;

//命令类
public class MyCommand implements Command{

    private Receiver receiver;

    public MyCommand(Receiver receiver) {
        this.receiver=receiver;
    }

    @Override
    public void exec() {
        //执行命令的方法
        //里面的是执行命令的人的动作
        receiver.action();
    }

}

发出命令的司令员

package command;

//发出命令(司令员)
public class Invoker {

    private Command command;  //接口更好的扩展性

    public Invoker(Command command) {
        this.command=command;
    }

    public void action(){
        command.exec();  //发出命令
    }
}

测试(Test)

package command;

public class Test {

    public static void main(String[] args) {

        Receiver receiver=new Receiver();       //接收命令的士兵

        Command command=new MyCommand(receiver);//命令发给接收者

        Invoker invoker=new Invoker(command);   //司令员发出命令

        invoker.action();       //发出命令的类,命令类,接收命令的类,三者相互解耦
    }
}

测试结果

Command received!

19.备忘录模式(Memento)

简单说明:保存一个对象的某个状态,以便在适当的时候恢复对象。在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

举例说明:
备忘录类(Memento)

package memento;

/**
 * Memento (备忘录模式):主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象
 * 通俗来讲:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储
 *        A的一些内部状态,类C呢,就是一个用来存储备忘录的,且只能存储,不能修改等操作
 * @author cx
 * Memento 是备忘录类
 */

public class Memento {

    private String value;

    public Memento(String value) {
        this.value=value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }



}

原始类(需要保存的Value)

package memento;

/**
 * Original 类是原始类,里面有需要保存的属性Value及创建一个备忘录类,用来保存value值
 *
 * @author cx
 *
 */
public class Original {

    private String value;

    public Original(String value) {
        this.value=value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public Memento createMemento(){
        //创建备忘录,并保存值在备忘录中
        return new Memento(value);
    }

    public void restoreMemento(Memento memento){
        //还原备忘录中保存的值
        this.value=memento.getValue();
    }

}

Storage(存储备忘录的类)

package memento;

/**
 * Storage 是存储备忘录的类,持有Memento类的实例
 * @author cx
 * 就是用来存储备忘录的类
 */
public class Storage {

    private Memento memento;

    public Storage(Memento memento){
        this.memento=memento;
    }

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }


}

测试(Test)

package memento;

public class Test {

    public static void main(String[] args) {

        //创建原始类
        Original original=new Original("egg");

        //创建备忘录
        Storage storage=new Storage(original.createMemento());

        //修改原始类的状态
        System.out.println("初始化状态为:"+original.getValue());
        original.setValue("df");
        System.out.println("修改后的状态为:"+original.getValue());

        //恢复原始类的状态
        original.restoreMemento(storage.getMemento());
        System.out.println("恢复后的状态为:"+original.getValue());

    }

}

测试结果

初始化状态为:egg
修改后的状态为:df
恢复后的状态为:egg

20.状态模式(State)

简单说明:类的行为是基于它的状态改变的。允许对象在内部状态发生改变时改变它的行为,将各种具体的状态抽象出来。

应用实例:打篮球的时候运动员可以有正常状态、不正常状态和超常状态。

先写一个State接口,内部隐藏一个Context 属性
举例说明:

package state;

public interface State {

    public void doAction(Context context);
}
package state;

public class Context {

    private State state;

    public Context() {
        state=null;  
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }


}

开始状态StartState类,实现State接口

package state;

public class StartState implements State{

    @Override
    public void doAction(Context context) {
        // TODO 自动生成的方法存根
        System.out.println("Player is in start state");
        context.setState(this);  //记住一定要将state传进来,不然会报空指针异常
    }

    @Override
    public String toString() {
        return "Start State";
    }
}

结束状态类(StopState)实现State接口

package state;

public class StopState implements State{

    @Override
    public void doAction(Context context) {
        // TODO 自动生成的方法存根
        System.out.println("Player is in Stop State");
        context.setState(this);//记住一定要将state传进来,不然会报空指针异常
    }

    @Override
    public String toString() {
        return "Stop State";
    }
}
package state;

public class Test {

    public static void main(String[] args) {
        Context context=new Context();

        StartState startState=new StartState();
        startState.doAction(context);

        System.out.println(context.getState().toString());

        StopState stopState=new StopState();
        stopState.doAction(context);

        System.out.println(context.getState().toString());
    }
}

测试结果

Player is in start state
Start State
Player is in Stop State
Stop State

21访问者模式(Visitor)

简单说明:主要将数据结构与数据操作分离,它改变了元素类的执行算法,通过这种方式,元素的执行算法可以随着访问者改变而改变。

举例说明:

package visitor;

/**
 * Visitor: 访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于
 *          数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。
 *          若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。
 * 优点:增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统
 *      数据结构。
 * 缺点:就是增加新的数据结构很困难。
 * 
 * @author cx
 * Visitor 存放要访问的对象
 */
public interface Visitor {

    public void visit(Subject sub);

}
package visitor;

public interface Subject {

    //accept方法,接受将要访问它的对象
    public void accept(Visitor visitor);

    //getSubject() 获取将要被访问的属性
    public String getSubject();
}
package visitor;

public class MyVisitor implements Visitor{

    //访问对象的方法
    @Override
    public void visit(Subject sub) {
        // TODO 自动生成的方法存根
        System.out.println("visit the subject:"+sub.getSubject());
    }


}
package visitor;

public class MySubject implements Subject{

    @Override
    public void accept(Visitor visitor) {
        // TODO 自动生成的方法存根
        visitor.visit(this);
    }

    @Override
    public String getSubject() {
        // TODO 自动生成的方法存根
        return "love";
    }

}
package visitor;

/**
 * 该模式适用场景:如果我们想为一个现有的类增加新功能,考虑这几个事情
 *  1.新功能会不会与现有功能出现兼容性的问题
 *  2.以后会不会再需要添加
 *  3.如果类不允许修改代码怎么办
 *  访问者模式适用于数据结构相对稳定的系统,把数据结构和算法解耦
 * @author cx
 *
 */
public class Test {

    public static void main(String[] args) {
        Visitor visitor=new MyVisitor();

        Subject subject=new MySubject();

        subject.accept(visitor);
    }
}

测试结果

visit the subject:love

22.中介者模式

简单说明:用一个中介对象来封装一系列的对象交互,中
介者使各对象不需要显示地相互引用,从而使耦合松散。

举例说明:

package mediator;

/**
 * 中介者模式:也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改
 *          一个对象,其它关联的对象都得进行修改。
 * 若使用中介者模式,只需关心和Mediator类的关系,具体类类之间的关系及调度交给Mediator就行。
 * @author cx
 *
 */
public interface Mediator {

    public void createMediator();

    public void workAll();

}
package mediator;

/**
 * User类统一接口,User1和User2分别是不同的对象,二者之间有关联,如果不采用中介者模式
 *         则需要二者相互持有引用,这样二者的耦合度很高,为了解耦,引入Mediator类,提供统一接口
 *     MyMediator为其实现类,里面持有User1和User2的实例,用来实现对User1和User2的控制
 *          这样User1 和User2两个对象相互独立,他们只需要保持好和Mediator之间的关系就行,剩下的全由
 *     MyMediator类来维护!
 * @author cx
 *
 */
public abstract class User {

    private Mediator mediator;

    public Mediator getMediator(){
        return mediator;
    }

    public User(Mediator mediator){
        this.mediator=mediator;
    }

    //抽象方法work()
    public abstract void work();
}
package mediator;

public class User1 extends User{

    public User1(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void work() {
        System.out.println("user1 exe!");
    }

}
package mediator;

public class User2 extends User{

    public User2(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void work() {
        System.out.println("user2 exe!");
    }

}
package mediator;

public class MyMediator implements Mediator{

    private User user1;
    private User user2;

    public User getUser1() {
        return user1;
    }

    public User getUser2() {
        return user2;
    }

    @Override
    public void createMediator(){
        user1=new User1(this);
        user2=new User2(this);
    }

    @Override
    public void workAll() {
        user1.work();
        user2.work();
    }

}
package mediator;

public class Test {

    public static void main(String[] args) {
        Mediator mediator=new MyMediator();
        mediator.createMediator();
        mediator.workAll();

    }
}

测试结果

user1 exe!
user2 exe!

23.解释器模式(Interpreter)

简单说明:提供了评估语言的语法或表达式的方式。跟解释器硬件有关,该模式用的比较少。

举例说明:

package interpreter;

/**
 * 解释器模式:一般应用在OOP开发的编译器的开发中,所以适用面比较窄。
 * @author cx
 *
 */
public interface Expression {

    public int interpret(Context context);
}
package interpreter;

public class Context {

    private int num1;
    private int num2;

    public Context(int num1,int num2){
        this.num1=num1;
        this.num2=num2;
    }

    public int getNum1() {
        return num1;
    }

    public void setNum1(int num1) {
        this.num1 = num1;
    }

    public int getNum2() {
        return num2;
    }

    public void setNum2(int num2) {
        this.num2 = num2;
    }

}
package interpreter;

public class Plus implements Expression{

    @Override
    public int interpret(Context context) {
        // TODO 自动生成的方法存根
        return context.getNum1()+context.getNum2();
    }

}
package interpreter;

public class Minus implements Expression{

    @Override
    public int interpret(Context context) {
        // TODO 自动生成的方法存根
        return context.getNum1()-context.getNum2();
    }

}
package interpreter;

public class Test {

    public static void main(String[] args) {
        int result=new Minus().
                interpret(new Context(new Plus().interpret(new Context(9, 2)), 8));
        System.out.println(result);
    }
}

测试结果

3

到这里23种设计模式总算写完了!!!

猜你喜欢

转载自blog.csdn.net/m0_37094131/article/details/70872461