设计模式-行为型模式

一、模板方法模式

定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下
重定义该算法的某些特定步骤

结构:
    抽象类:负责给出一个算法的轮廓和骨架。由一个模板方法和若干个基本方法构成。
         模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
         基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种
                 抽象方法:一个抽象方法由抽象类声明、由其具体子类实现
                 具体方法:一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接     
                          继承
                 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种
    具体子类:实现抽象类中所定义的抽象方法和钩子方法,他们是一个顶级逻辑的组成部分
    
优点:
    1.提高代码复用性
    2.实现了反转控制
    
缺点:
    1.对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象
    2.父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,提高了代码阅读的难度
    
使用场景:
       1.算法的整体步骤很固定,但其中个别部分易变时
       2.需要通过子类来决定父类算法中某个步骤是否执行
/**
 * 抽象类 : 定义模板方法和基本方法
 */
public abstract class AbstractCook {

    //模板方法 算法的执行流程,不允许子类重写
    public final void cook(){
        pourOil();
        heatOil();
        addFood();
        addSauce();
        fry();
    }


    public void pourOil(){
        System.out.println("倒油");
    }

    public void heatOil(){
        System.out.println("热油");
    }

    //加入原材料
    public abstract void addFood();

    //加入调料
    public abstract void addSauce();

    public void fry(){
        System.out.println("炒菜");
    }
}

/**
 * 具体子类 回锅肉
 */
public class TwiceCookedPork extends AbstractCook{

    @Override
    public void addFood() {
        System.out.println("将提前煮好的肉放入锅里");
    }

    @Override
    public void addSauce() {
        System.out.println("加入郫县豆瓣酱、葱、姜、蒜、辣椒末");
    }
}

/**
 * 具体子类 辣子鸡丁
 */
public class SpicyChicken extends AbstractCook{

    @Override
    public void addFood() {
        System.out.println("加入鸡丁和辣椒");
    }

    @Override
    public void addSauce() {
        System.out.println("加入大量辣椒和花椒");
    }
}

public class Test {

    public static void main(String[] args) {
        //回锅肉
        AbstractCook cook1 = new TwiceCookedPork();
        cook1.cook();

        System.out.println("------------------------------------");

        //辣子鸡丁
        AbstractCook cook2 = new TwiceCookedPork();
        cook2.cook();
    }

}

二、策略模式

该模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响使用算法的客户。
策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,
并委派给不同的对象对这些算法进行管理

结构:
    抽象策略类:通常由一个接口或抽象类实现,给出所有具体策略类所需要的接口
    具体策略类:实现了抽象策略定义的接口,提供具体的算法实现或行为
    环境类:持有一个策略类的引用,最终给客户端调用
    
优点:
    1.策略类之间可以自由切换,因为它们都实现同一个接口
    2.易于扩展,增加一个新的策略只需要添加一个具体的策略类即可,符合开闭原则。
      充分体现了面向对象设计思想

缺点:
    1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类
    2.策略模式将造成很多策略类,可以通过享元模式在一定程度上减少对象的数量

使用场景:
       1.一个系统需要动态的在几种算法中选择一种时,可将每个算法封装到策略类中
       2.一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,
         可将每个条件分 移入它们各自的策略类中以代替这些条件语句
       3.系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时
       4.多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为
/**
 * 抽象策略类
 */
public interface Strategy {

    void show();

}

/**
 * 具体策略类 封装算法
 */
public class StrategyA implements Strategy{

    @Override
    public void show() {
        System.out.println("买一送一");
    }
}

/**
 * 具体策略类 封装算法
 */
public class StrategyB implements Strategy{

    @Override
    public void show() {
        System.out.println("满两百减五十");
    }
}

/**
 * 具体策略类 封装算法
 */
public class StrategyC implements Strategy{

    @Override
    public void show() {
        System.out.println("打五折");
    }
}

/**
 * 环境类
 */
public class SaleMan {

    private Strategy strategy;

    public SaleMan() {
    }

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

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    //展示促销活动
    public void salesManShow(){
        strategy.show();
    }
}

public class Test {

    public static void main(String[] args) {
        SaleMan saleMan = new SaleMan();
        
        Strategy a = new StrategyA();
        //Strategy b = new StrategyB();
        //Strategy c = new StrategyC();
        
        saleMan.setStrategy(a);
        //saleMan.setStrategy(b);
        //saleMan.setStrategy(c);
        saleMan.salesManShow();
    }

}

三、命令模式

将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,
这样方便将命令对象进行存储、传递、调用、增加与管理

结构:
    抽象命令类角色:定义命令的接口,声明执行的方法
    具体命令角色:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作
    接收者角色:真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能
    请求者角色:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发 
              命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口
    
优点:
    1.降低系统的耦合度。将调用操作的对象与实现操作的对象解耦
    2.增加或删除命令非常方便。不会影响其他类,满足开闭原则,对扩展比较灵活
    3.可以实现宏命令。命令模式可以和组合模式结合,将多个命令装配成为一个组合命令,即宏命令
    4.方便实现 undo 和 redo 操作
    
缺点:
    1.使用命令模式可能会导致某些系统有过多的命令类
    2.系统结构更加复杂
    
使用场景:
       1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
       2.系统需要在不同的时间指定请求、将请求排队和执行请求
       3.系统需要支持命令的撤销操作和恢复操作
/**
 * 抽象命令角色
 */
public interface Command {

    void execute();

}

/**
 * 具体命令类
 */
public class OrderCommand implements Command{

    //持有接收者对象
    private SeniorChef seniorChef;
    //持有订单对象
    private Order order;

    public OrderCommand(SeniorChef seniorChef, Order order) {
        this.seniorChef = seniorChef;
        this.order = order;
    }

    @Override
    public void execute() {
        System.out.println(order.getDiningTable() + " 桌的订单 : ");
        Map<String, Integer> map = order.getMap();
        //遍历菜品集合
        for (String foodName : map.keySet()){
            seniorChef.makeFood(foodName,map.get(foodName));
        }
        System.out.println(order.getDiningTable() + " 桌的饭准备完毕");
    }
}

/**
 * 订单类
 */
public class Order {

    private int diningTable;
    private Map<String,Integer> map = new HashMap<>();

    public int getDiningTable() {
        return diningTable;
    }

    public void setDiningTable(int diningTable) {
        this.diningTable = diningTable;
    }

    public Map<String, Integer> getMap() {
        return map;
    }

    public void setFood(String name,int num) {
        map.put(name,num);
    }
}

/**
 * 接收者角色 厨师
 */
public class SeniorChef {

    public void makeFood(String name,int num){
        System.out.println(num + "份 : " + name);
    }

}

/**
 * 请求者角色 服务员
 */
public class Waiter {

    //持有多个命令对象
    private List<Command> list = new ArrayList<>();

    public void setCommand(Command command){
        list.add(command);
    }

    //发起命令的功能
    public void orderUp(){
        System.out.println("新订单来了....");
        for (Command command : list){
            if (command != null){
                command.execute();
            }
        }
    }
}

public class Test {

    public static void main(String[] args) {
        Order order1 = new Order();
        order1.setDiningTable(1);
        order1.setFood("辣子鸡丁",1);
        order1.setFood("米饭",2);
        order1.setFood("可口可乐",2);

        Order order2 = new Order();
        order2.setDiningTable(2);
        order2.setFood("烧烤",1);
        order2.setFood("烤饼",1);
        order2.setFood("果啤",2);

        SeniorChef seniorChef = new SeniorChef();

        OrderCommand command1 = new OrderCommand(seniorChef,order1);
        OrderCommand command2 = new OrderCommand(seniorChef,order2);

        Waiter waiter = new Waiter();
        waiter.setCommand(command1);
        waiter.setCommand(command2);

        //服务员发起命令
        waiter.orderUp();
    }

}

四、责任链模式

为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住下一个对象的引用
而形成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止

结构:
    抽象处理者角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接
    具体处理者角色:实现抽象处理者角色的处理方法,判断能否处理本次请求,如果可以处理则处理请求,
                  否则将该请求转给它的后继者
    客户类角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心请求的处理细节和请求的传递过程
    
优点:
    1.降低了对象之间的耦合度。降低了请求发送者和接收者的耦合度
    2.增强了系统的可扩展性
    3.增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态的改变链内的成员或者修改他们的次序,
      也 可以动态地新增或者删除责任
    4.责任链简化了对象之间的连接。一个对象只需保持一个指向其后继者的引用,不需要保持其它处理者的引用
    5.责任分担。每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,
       符合类的单一职责原则
    
缺点:
    1.不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,
      该请求可能一直传到链的末端都得不到处理
    2.对比较长的责任链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响
    3.职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出 
      错
//请假条类
public class LeaveRequest {

    private String name;
    private int num;
    private String content;

    public LeaveRequest(String name, int num, String content) {
        this.name = name;
        this.num = num;
        this.content = content;
    }

    public String getName() {
        return name;
    }

    public int getNum() {
        return num;
    }

    public String getContent() {
        return content;
    }
}

/**
 * 抽象处理者
 */
public abstract class Handler {

    public final static int NUM_ONE = 1;
    public final static int NUM_THREE = 3;
    public final static int NUM_SEVEN = 7;

    //可以处理的请求天数区间
    private int numStart;
    private int numEnd;

    //声明后继者
    private Handler nextHandler;

    public Handler(int numStart) {
        this.numStart = numStart;
    }

    public Handler(int numStart, int numEnd) {
        this.numStart = numStart;
        this.numEnd = numEnd;
    }

    //设置后继者
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    //处理任务的方法
    public abstract void handler(LeaveRequest request);

    //提交任务
    public final void submit(LeaveRequest request){
        //当前类进行处理
        handler(request);
        if (nextHandler != null && request.getNum() > numEnd){
            //提交给后继者进行处理
            nextHandler.submit(request);
        } else {
            System.out.println("流程结束...");
        }
    }
}

/**
 * 具体处理者角色
 */
public class GroupLeader extends Handler{

    public GroupLeader(){
        super(0,Handler.NUM_ONE);
    }

    @Override
    public void handler(LeaveRequest request) {
        System.out.println(request.getName() + "请假" + request.getNum() + "天," + request.getContent());
        System.out.println("小组长审批 : 通过");
    }
}

/**
 * 具体处理者角色
 */
public class Manager extends Handler{

    public Manager(){
        super(Handler.NUM_ONE,Handler.NUM_THREE);
    }

    @Override
    public void handler(LeaveRequest request) {
        System.out.println(request.getName() + "请假" + request.getNum() + "天," + request.getContent());
        System.out.println("部门经理审批 : 通过");
    }
}

/**
 * 具体处理者角色
 */
public class GeneralManager extends Handler{

    public GeneralManager(){
        super(Handler.NUM_THREE,Handler.NUM_SEVEN);
    }

    @Override
    public void handler(LeaveRequest request) {
        System.out.println(request.getName() + "请假" + request.getNum() + "天," + request.getContent());
        System.out.println("总经理审批 : 通过");
    }
}

public class Test {

    public static void main(String[] args) {
        //创建请假条对象
        LeaveRequest request = new LeaveRequest("老王",2,"去做隔壁老王");

        //创建审批人对象
        Handler groupLeader = new GroupLeader();
        Handler manager = new Manager();
        Handler generalManager = new GeneralManager();

        //设置处理者链
        groupLeader.setNextHandler(manager);
        manager.setNextHandler(generalManager);

        //提交请假申请
        groupLeader.submit(request);
    }

}

五、状态模式

对有状态的对象,把复杂的判断逻辑提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为

结构:
    环境角色:也称为上下文,它定义了客户程序需要的接口,维护一个当前状态,并将与状态相关的操作委托
             给当前状态对象来处理
    抽象状态角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为
    具体状态角色:实现抽象状态所对应的行为
    
优点:
    1.将所有与某个状态有关的行为放到一个类中,并且可以方便的增加新的状态,只需要改变对象状态即可改变
      对象的行为
    2.允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块

缺点:
    1.状态模式的使用必然会增加系统和对象的个数
    2.状态模式的结构和实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
    3.状态模式对开闭原则的支持并不太好
    
使用场景:
       1.当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用
         状态模式
       2.一个操作中含有庞大的分支结构,并且这些分支取决于对象的状态时
/**
 * 抽象状态角色
 */
public abstract class LiftState {

    public Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    //开启
    public abstract void open();

    //关闭
    public abstract void close();

    //运行
    public abstract void run();

    //停止
    public abstract void stop();
}

/**
 * 具体状态角色
 */
public class OpeningState extends LiftState{

    //当前状态要执行的方法
    @Override
    public void open() {
        System.out.println("电梯开启...");
    }

    @Override
    public void close() {
        //修改状态
        context.setLiftState(Context.CLOSING_STATE);
        //调用当前状态中的context中的对应的close方法
        context.close();
    }

    @Override
    public void run() {
        //什么都不做
    }

    @Override
    public void stop() {
        //什么都不做
    }
}

/**
 * 具体状态角色
 */
public class StoppingState extends LiftState{

    @Override
    public void open() {
        //修改状态
        context.setLiftState(Context.RUNNING_STATE);
        context.run();
    }

    @Override
    public void close() {
        context.setLiftState(Context.CLOSING_STATE);
        context.close();
    }

    @Override
    public void run() {
        //修改状态
        context.setLiftState(Context.RUNNING_STATE);
        context.run();
    }

    @Override
    public void stop() {
        System.out.println("电梯停止了");
    }
}

/**
 * 具体状态角色
 */
public class RunningState extends LiftState{

    @Override
    public void open() {
        //什么都不做
    }

    @Override
    public void close() {
        //什么都不做
    }

    @Override
    public void run() {
        System.out.println("电梯正在运行");
    }

    @Override
    public void stop() {
        //修改状态
        context.setLiftState(Context.STOPPING_STATE);
        context.stop();
    }
}

/**
 * 具体状态角色
 */
public class ClosingState extends LiftState{

    @Override
    public void open() {
        context.setLiftState(Context.OPENING_STATE);
        context.open();
    }

    @Override
    public void close() {
        System.out.println("电梯门关闭了");
    }

    @Override
    public void run() {
        context.setLiftState(Context.RUNNING_STATE);
        context.run();
    }

    @Override
    public void stop() {
        context.setLiftState(Context.STOPPING_STATE);
        context.stop();
    }
}

/**
 * 环境角色
 */
public class Context {

    //定义对应状态对象的常量
    public final static OpeningState OPENING_STATE = new OpeningState();
    public final static ClosingState CLOSING_STATE = new ClosingState();
    public final static RunningState RUNNING_STATE = new RunningState();
    public final static StoppingState STOPPING_STATE = new StoppingState();

    //定义一个当前电梯状态变量
    private LiftState liftState;

    public LiftState getLiftState() {
        return liftState;
    }

    public void setLiftState(LiftState liftState) {
        this.liftState = liftState;
        //设置当前状态对象中的Context对象
        this.liftState.setContext(this);
    }

    public void open(){
        liftState.open();
    }

    public void close(){
        liftState.close();
    }

    public void run(){
        liftState.run();
    }

    public void stop(){
        liftState.stop();
    }
}

public class Test {

    public static void main(String[] args) {

        //创建环境角色对象
        Context context = new Context();

        //设置当前电梯状态 - 运行
        context.setLiftState(Context.CLOSING_STATE);

        context.open();
        context.run();
        context.close();
        context.stop();
    }

}

六、观察者模式

又被称为 发布-订阅 模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己

结构:
    Subject:抽象主题,抽象主题把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,
             抽象主题提供一个接口,可以增加和删除观察者对象
    ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,
                      给所有注册过的观察者发送通知
    Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时
              更新自己
    ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的  
                      状态
    
优点:
    1.降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系
    2.被观察者发送通知,所有注册的观察者都会收到信息
    
缺点:
    1.如果观察者非常多的话,那么所有观察者收到被观察者发送的通知会耗时
    2.如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃
    
使用场景:
       1.对象间存在一对多关系,一个对象的状态发生改变会影响其他对象
       2.当一个抽象模型有两个方面,其中一个方面依赖于另一方面
/**
 * 抽象主题角色
 */
public interface Subject {

    //添加观察者对象
    void attach(Observer observer);

    //移除观察者对象
    void detach(Observer observer);

    //通知观察者更新消息
    void notify(String msg);
}

/**
 * 具体主题角色类
 */
public class ConcreteSubject implements Subject{

    //存储多个观察者对象
    private List<Observer> list = new ArrayList<>();

    @Override
    public void attach(Observer observer) {
        list.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        list.remove(observer);
    }

    @Override
    public void notify(String msg) {
        for (Observer cur : list){
            cur.update(msg);
        }
    }
}

/**
 * 抽象观察者角色
 */
public interface Observer {

    void update(String msg);

}

/**
 * 具体观察者角色类
 */
public class WeiXinUser implements Observer{

    private String name;

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

    @Override
    public void update(String msg) {
        System.out.println(name + "-" + msg);
    }
}

public class Test {

    public static void main(String[] args) {

        Subject subject = new ConcreteSubject();

        subject.attach(new WeiXinUser("老王"));
        subject.attach(new WeiXinUser("大白"));

        subject.notify("来斗地主");
    }

}

七、中介者模式

定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互

结构:
    抽象中介者角色:中介者地接口,提供了同事对象注册与转发同事对象信息的抽象方法
    具体中介者角色:实现中介者接口,定义一个 list 来管理同事对象,协调各个同事角色之间的交互关系,
                  因此它依赖于同事角色
    抽象同事类角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,
                  实现所有相互影响的同事类的公共功能
    具体同事类角色:实现抽象同事类,当需要与其它同事对象交互时,由中介者对象负责后续的交互
    
优点:
    1.松散耦合。中介者模式通过把多个同事之间的交互封装到中介者对象里面,从而使得同事对象之间松散耦合,
       基本上可以做到互补依赖。这样一来,同事对象就可以独立的变化和复用
    2.集中控制交互。多个同事对象的交互,被封装在中介者对象里面集中管理,使得这些交互行为发生变化的时  
       候,只需要修改中介者对象就可以了。
    3.一对多关联转变为一对一的关联。
    
缺点:
    当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护
    
使用场景:
       1.系统中对象之间存在复杂的引用关系,系统结构混乱且难以理解
       2.当想创建一个运行于多个类之间的对象,又不想生成新的子类时
/**
 * 抽象中介者角色
 */
public abstract class Mediator {

    public abstract void construct(String msg,Person person);

}

/**
 * 具体中介者角色
 */
public class MediatorStructure extends Mediator{

    private HouseOwner houseOwner;
    private Tenant tenant;

    public HouseOwner getHouseOwner() {
        return houseOwner;
    }

    public void setHouseOwner(HouseOwner houseOwner) {
        this.houseOwner = houseOwner;
    }

    public Tenant getTenant() {
        return tenant;
    }

    public void setTenant(Tenant tenant) {
        this.tenant = tenant;
    }

    @Override
    public void construct(String msg, Person person) {
        if(person == houseOwner) {
            tenant.getMessage(msg);
        } else {
            houseOwner.getMessage(msg);
        }
    }
}

/**
 * 抽象同事类角色
 */
public abstract class Person {

    public String name;
    public Mediator mediator;

    public Person(String name, Mediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }
}

/**
 * 具体同事类角色
 */
public class Tenant extends Person{

    public Tenant(String name, Mediator mediator) {
        super(name, mediator);
    }

    //和中介沟通
    public void construct(String msg){
        mediator.construct(msg,this);
    }

    //获取信息
    public void getMessage(String msg){
        System.out.println("租房者 : " + name + ",获取到的信息是 : " + msg);
    }
}

/**
 * 具体同事类角色
 */
public class HouseOwner extends Person {

    public HouseOwner(String name, Mediator mediator) {
        super(name, mediator);
    }

    //和中介沟通
    public void construct(String msg){
        mediator.construct(msg,this);
    }

    //获取信息
    public void getMessage(String msg){
        System.out.println("房主 : " + name + ",获取到的信息是 : " + msg);
    }
}

public class Test {

    public static void main(String[] args) {
        //中介对象
        MediatorStructure mediator = new MediatorStructure();

        Tenant tenant = new Tenant("老王",mediator);
        HouseOwner houseOwner = new HouseOwner("绿帽子",mediator);

        mediator.setTenant(tenant);
        mediator.setHouseOwner(houseOwner);

        tenant.construct("我要租房子");
        houseOwner.construct("我给你租");
    }

}

八、迭代器模式

提供给一个对象来顺序访问聚合对象中的一系列数据,而不是暴露对象内部的表示

结构:
    抽象聚合角色:定义存储、添加、删除聚合元素以及创建迭代器对象的接口
    具体聚合角色:实现抽象聚合角色,返回一个具体的迭代器实例
    抽象迭代器角色:定义访问和遍历聚合元素的接口,
    具体迭代器:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置
    
优点:
    1.它支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。在迭代器模式中只
      需要 用一个不同的迭代器来替换原有迭代器即可改变遍历算法,我们也可以自己定义迭代器的子类以支持
      新的遍历方式
    2.迭代器简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再自行提供数据遍历等方法,这样
      可以简化聚合类的设计
    3.在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,
      满足开闭原则的要求
    
缺点:
    增加了类的个数,这在一定程度上增加了系统的复杂性
    
使用场景:
       1.当需要为聚合对象提供多种遍历方式时
       2.当需要为遍历不同的聚合结构提供一个统一的接口时
       3.当访问一个聚合对象的内容而无须暴露其内部细节的表示时
/**
 * 抽象迭代器角色
 */
public interface StudentIterator {

    //判断是否还有元素
    boolean hashNext();

    //获取下一个元素
    Student next();

}

/**
 * 具体迭代器角色类
 */
public class StudentIteratorImpl implements StudentIterator{

    private List<Student> list;
    private int position = 0;//记录遍历时的位置

    public StudentIteratorImpl(List<Student> list) {
        this.list = list;
    }

    @Override
    public boolean hashNext() {
        return position < list.size();
    }

    @Override
    public Student next() {
        Student student = list.get(position);
        position++;
        return student;
    }
}

/**
 * 抽象聚合角色
 */
public interface StudentAggregate {

    //添加学生
    void addStudent(Student student);

    //删除学生
    void deleteStudent(Student student);

    //获取迭代器对象
    StudentIterator getStudentIterator();

}

/**
 * 具体聚合角色
 */
public class StudentAggregateImpl implements StudentAggregate{

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

    @Override
    public void addStudent(Student student) {
        list.add(student);
    }

    @Override
    public void deleteStudent(Student student) {
        list.remove(student);
    }

    //获取迭代器对象
    @Override
    public StudentIterator getStudentIterator() {
        return new StudentIteratorImpl(list);
    }
}

public class Student {

    private String name;
    private int num;

    public Student() {
    }

    public Student(String name, int num) {
        this.name = name;
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "Student{" +
            "name='" + name + '\'' +
            ", num=" + num +
            '}';
    }
}

public class Test {

    public static void main(String[] args) {
        //创建聚合对象
        StudentAggregate aggregate = new StudentAggregateImpl();
        aggregate.addStudent(new Student("张三",1));
        aggregate.addStudent(new Student("李四",2));
        aggregate.addStudent(new Student("王麻子",3));

        //获取迭代去对象
        StudentIterator iterator = aggregate.getStudentIterator();

        //遍历
        while (iterator.hashNext()){
            System.out.println(iterator.next());
        }
    }

}

九、访问者模式

封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作

结构:
    抽象访问者角色:定义了对每一个元素访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲与
                   元素类个数是一样的,访问者模式要求元素类的个数不能改变
    具体访问者角色:给出对每一个元素类访问时所产生的具体行为
    具体元素角色:定义了一个接受访问者的方法,每一个元素都可以被访问者访问
    具体元素角色:提供接受访问方法的具体实现,通常情况下是使用访问者提供的访问该元素类的方法
    对象结构角色:一个具有容器性质或者符合对象特性的类,它含有一组元素,并且可以迭代这些元素,
                供访问者 访问
    
优点:
    1.扩展性好。在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能
    2.复用性好。通过访问者来定义整个对象结构通用的功能,从而提高复用程度
    3.分离无关行为。通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,
      这样每一个访问 者的功能都比较单一
    
缺点:
    1.对象结构变化很困难。每增加一个新的元素类,都要在每一个具体访问者中增加相应的具体操作
    2.违反了依赖倒转原则。访问者模式依赖了具体类,而没有依赖抽象类
    
使用场景:
       对象结构相对稳定,但其操作算法经常变化的程序
/**
 * 抽象元素角色
 */
public interface Animal {

    //接受访问者访问的功能
    void accept(Person person);

}

/**
 * 具体元素角色
 */
public class Dog implements Animal{

    @Override
    public void accept(Person person) {
        person.feed(this);
        System.out.println("给狗喂食");
    }
}

/**
 * 具体元素角色
 */
public class Cat implements Animal{

    @Override
    public void accept(Person person) {
        person.feed(this);
        System.out.println("给猫喂食");
    }
}

/**
 * 抽象访问者角色
 */
public interface Person {

    //喂狗
    void feed(Dog dog);

    //喂猫
    void feed(Cat cat);

}

/**
 * 具体访问者角色
 */
public class Owner implements Person{

    @Override
    public void feed(Dog dog) {
        System.out.print("主人 : ");
    }

    @Override
    public void feed(Cat cat) {
        System.out.print("主人 : ");
    }
}

/**
 * 具体访问者角色
 */
public class Customer implements Person{

    @Override
    public void feed(Dog dog) {
        System.out.println("客人 : ");
    }

    @Override
    public void feed(Cat cat) {
        System.out.println("客人 : ");
    }
}

/**
 * 对象结构角色
 */
public class Home {

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

    //添加元素
    public void add(Animal animal){
        list.add(animal);
    }

    public void action(Person person){
        //遍历集合,获取每一个元素,让访问者访问每一个元素
        for (Animal animal : list) {
            animal.accept(person);
        }
    }

}

public class Test {

    public static void main(String[] args) {
        //创建home对象
        Home home = new Home();

        //添加元素
        home.add(new Dog());
        home.add(new Cat());

        Owner owner = new Owner();
        home.action(owner);
    }

}

十、备忘录模式

又叫快照模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,
以便以后需要时能将该对象恢复到原先保存的状态

结构:
    发起人角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,它可以访问备忘录里的 
               所有信息
    备忘录角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人
    管理者角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改
   
    
优点:
    1.提供了一种可以恢复状态的机制。当用户需要时能够比较方便的将数据恢复到某个历史状态
    2.实现了内部封装的状态。除了创建它的发起人之外,其他对象都不能够访问这些状态信息
    3.简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,
      并由管理者进行管理,这符合单一职责原则
    
缺点:
    资源消耗大
    
使用场景:
       1.需要保存与恢复数据的场景
       2.需要提供一个可回滚操作的场景
//白箱备忘录
/**
 * 发起人角色
 */
public class GameRole {

    private int vit;//生命力
    private int atk;//攻击力
    private int def;//防御力

    //初始化内部状态
    public void initState() {
        vit = 100;
        atk = 100;
        def = 100;
    }

    //战斗
    public void fight(){
        vit = 0;
        atk = 0;
        def = 0;
    }

    //保存角色状态功能
    public RoleStateMemento saveState() {
        return new RoleStateMemento(vit,atk,def);
    }

    //恢复角色状态
    public void recoverState (RoleStateMemento roleStateMemento){
        this.vit = roleStateMemento.getVit();
        this.atk = roleStateMemento.getAtk();
        this.def = roleStateMemento.getDef();
    }

    //展示状态
    public void stateDisplay(){
        System.out.println("生命力 : " + vit);
        System.out.println("攻击力 : " + atk);
        System.out.println("防御力 : " + def);
    }

    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getAtk() {
        return atk;
    }

    public void setAtk(int atk) {
        this.atk = atk;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }
}

/**
 * 备忘录角色类
 */
public class RoleStateMemento {

    private int vit;//生命力
    private int atk;//攻击力
    private int def;//防御力

    public RoleStateMemento() {
    }

    public RoleStateMemento(int vit, int atk, int def) {
        this.vit = vit;
        this.atk = atk;
        this.def = def;
    }

    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getAtk() {
        return atk;
    }

    public void setAtk(int atk) {
        this.atk = atk;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }
}

/**
 * 管理者角色
 */
public class RoleStateCaretaker {

    private RoleStateMemento roleStateMemento;

    public RoleStateMemento getRoleStateMemento() {
        return roleStateMemento;
    }

    public void setRoleStateMemento(RoleStateMemento roleStateMemento) {
        this.roleStateMemento = roleStateMemento;
    }
}

public class Test {

    public static void main(String[] args) {
        System.out.println("--------------战斗前----------------");
        GameRole gameRole = new GameRole();
        gameRole.initState();//初始化状态
        gameRole.stateDisplay();

        //备份内部状态
        RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();//管理者角色
        roleStateCaretaker.setRoleStateMemento(gameRole.saveState());

        //战斗
        gameRole.fight();

        System.out.println("--------------战斗后----------------");
        gameRole.stateDisplay();

        System.out.println("-------------恢复状态---------------");
        gameRole.recoverState(roleStateCaretaker.getRoleStateMemento());
        gameRole.stateDisplay();
    }

}



//黑箱备忘录
/**
 * 备忘录接口,对外提供窄接口
 */
public interface Memento {

}

/**
 * 发起人角色
 */
public class GameRole {

    private int vit;//生命力
    private int atk;//攻击力
    private int def;//防御力

    //初始化内部状态
    public void initState() {
        vit = 100;
        atk = 100;
        def = 100;
    }

    //战斗
    public void fight(){
        vit = 0;
        atk = 0;
        def = 0;
    }

    //保存角色状态功能
    public Memento saveState() {
        return new RoleStateMemento(vit,atk,def);
    }

    //恢复角色状态
    public void recoverState (Memento memento){
        RoleStateMemento roleStateMemento = (RoleStateMemento) memento;
        this.vit = roleStateMemento.getVit();
        this.atk = roleStateMemento.getAtk();
        this.def = roleStateMemento.getDef();
    }

    //展示状态
    public void stateDisplay(){
        System.out.println("生命力 : " + vit);
        System.out.println("攻击力 : " + atk);
        System.out.println("防御力 : " + def);
    }

    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getAtk() {
        return atk;
    }

    public void setAtk(int atk) {
        this.atk = atk;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }

    private class RoleStateMemento implements Memento {

        private int vit;//生命力
        private int atk;//攻击力
        private int def;//防御力

        public RoleStateMemento() {
        }

        public RoleStateMemento(int vit, int atk, int def) {
            this.vit = vit;
            this.atk = atk;
            this.def = def;
        }

        public int getVit() {
            return vit;
        }

        public void setVit(int vit) {
            this.vit = vit;
        }

        public int getAtk() {
            return atk;
        }

        public void setAtk(int atk) {
            this.atk = atk;
        }

        public int getDef() {
            return def;
        }

        public void setDef(int def) {
            this.def = def;
        }
    }
}

/**
 * 管理者角色
 */
public class RoleStateCaretaker {

    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

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

public class Test {

    public static void main(String[] args) {
        System.out.println("--------------战斗前----------------");
        GameRole gameRole = new GameRole();
        gameRole.initState();//初始化状态
        gameRole.stateDisplay();

        //备份内部状态
        RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();//管理者角色
        roleStateCaretaker.setMemento(gameRole.saveState());

        //战斗
        gameRole.fight();

        System.out.println("--------------战斗后----------------");
        gameRole.stateDisplay();

        System.out.println("-------------恢复状态---------------");
        gameRole.recoverState(roleStateCaretaker.getMemento());
        gameRole.stateDisplay();
    }

}

十一、解释器模式

给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子

结构:
    抽象表达式角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()
    终结符表达式角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符
                   都有一个具体终结表达式与之相对应
    非终结符表达式角色:用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式
    环境角色:通常包含各个解释器需要的数据或是功能,一般用来传递被所有解释器共享的数据,后边的解释器可
             以从这里获取这些值
    客户端:主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解  
           释方法,也可以通过环境角色间接访问解释器的解释方法
    
优点:
    1.易于改变和扩展文法。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变
       扩展文法。每一条文法规则都可以表示为一个类,因此可以方便的实现一个简单的语言
    2.改变文法较为容易。在抽象语法树中每一个表达式节点类的实现都是相似的,这些类的代码编写都不会特别复
       杂
    3.增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要增加一个新的终结符表达式或
      非终结符表达式类,原有表达式类代码无需修改,符合开闭原则

缺点:
    1.对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法
       规则,类的个数将会急剧增加,导致系统难以管理和维护
    2.执行效率低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,
       而且代码的调试过程也比较麻烦
    
使用场景:
       1.当语言文法较为简单,且执行效率不是关键问题时
       2.当问题重复出现,且可以用一种简单的语言来进行表达时
       3.当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树时
/**
 * 抽象表达式角色
 */
public abstract class AbstractExpression {

    public abstract int interpret(Context context);

}

/**
 * 封装变量的类 终结符表达式角色
 */
public class Variable extends AbstractExpression{

    //声明存储变量名的成员变量
    private String name;

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

    @Override
    public int interpret(Context context) {
        //直接返回变量的值
        return context.getValue(this);
    }

    @Override
    public String toString() {
        return name;
    }
}

/**
 * 加法表达式类 非终结符表达式角色
 */
public class Plus extends AbstractExpression{

    // + 左边的表达式
    private AbstractExpression left;
    // + 右边的表达式
    private AbstractExpression right;

    public Plus(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Context context) {
        return left.interpret(context) + right.interpret(context);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " + " + right.toString() + ")";
    }
}

/**
 * 减法表达式类 非终结符表达式角色
 */
public class Minus extends AbstractExpression{

    // - 左边的表达式
    private AbstractExpression left;
    // - 右边的表达式
    private AbstractExpression right;

    public Minus(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Context context) {
        return left.interpret(context) - right.interpret(context);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " - " + right.toString() + ")";
    }
}

/**
 * 环境角色类
 */
public class Context {

    //用来存储变量及对应的值
    private Map<Variable,Integer> map = new HashMap<>();

    //添加变量
    public void assign(Variable key,int value){
        map.put(key,value);
    }

    //根据变量获取对应的值
    public int getValue(Variable key){
        return map.get(key);
    }

}

public class Test {

    public static void main(String[] args) {
        //创建环境对象
        Context context = new Context();

        //创建多个变量对象
        Variable a = new Variable("a");
        Variable b = new Variable("b");
        Variable c = new Variable("c");
        Variable d = new Variable("d");

        //将变量存储到环境对象中
        context.assign(a,1);
        context.assign(b,2);
        context.assign(c,3);
        context.assign(d,4);

        //获取抽象语法树 a - b - c + d
        AbstractExpression expression = new Minus(a,new Plus(new Minus(b,c),d));

        //计算
        int ans = expression.interpret(context);

        System.out.println(expression + " = " + ans);

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cw旧巷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值