设计模式【二】行为型模式(处理程序中特定类型的操作的对象)

1、策略模式(Strategy Pattern)

1.1策略模式的定义
对于同一项任务,可以由多种方式来完成而这每一种方式称为一个策略。根据实际环境的不同来选择不同的策略来完成该任务。定义一些独立的类来封装不同的具体实现算法,每一个封装算法的类称为策略。
其定义为:定义一系列算法,从概念上看这些算法完成相同的工作,只是具体的实现不同,它们之间可以互相替换。
1.2策略模式的类图
这里Strategy是抽象策略类,用来约束具体的实现算法;ConcreteStrategyA是具体的实现算法;Context用来和具体的实现算法进行交互
在这里插入图片描述
1.3策略模式的代码分析
这里我们以冒泡排序、选择排序和插入排序为例(注:这里的数组全是int数组)
首先我们定义排序的接口

public interface Sort{
	int [] sort(int [] arr);
}

然后我们让BubbleSort、SelectionSort和InsertionSort来实现Sort接口

public class BubbleSort implements Sort {
    @Override
    public int[] sort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        return arr;
    }
}
public class InsertionSort implements Sort {
    @Override
    public int[] sort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int preIndex = i - 1;
            int curentValue = arr[i];
            while (preIndex >= 0 && curentValue < arr[preIndex]) {
                arr[preIndex+1] = arr[preIndex];
                preIndex--;
            }
            arr[preIndex+1] = curentValue;
        }
        return arr;
    }
}
public class SelectionSort implements Sort {
    @Override
    public int[] sort(int[] arr) {
        for(int i=0;i<arr.length-1;i++){
            int minIndex = i;
            for(int j=i+1;j<arr.length;j++){
                if(arr[j]<arr[minIndex]){
                    minIndex = j;
                }
            }
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
        return arr;
    }
}

然后使用构建策略上下文管理器StrategyContext,将Sort接口的实现类传递进来。

public class StrategyContext {
    private Sort ISort;

    public StrategyContext(Sort sort) {
        this.ISort = sort;
    }

    public StrategyContext() {
    }

    public int[] contextMethod(int[] arr) {
        return ISort.sort(arr);
    }
}

1.4策略模式的优缺点
优点:完美支持了OOP中的开闭原则;提供了管理算法簇的方法;避免使用多重条件转移语句
缺点:需要客户端知道所有的策略类并决定使用哪一个策略类;增加了类的数量,如果策略很多的话就会造成对象的数量增加

2、观察者模式(Observer Pattern)

2.1观察者模式定义
观察者模式:又称为发布-订阅模式,它建立了的一种一对多的对象依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将做出相应的反应。这里发生改变的对象成为观察目标,被通知的对象称为观察者。
2.2观察者模式的结构
观察者模式结构图
Subject是抽象的目标,ConcreteSubject是具体的观察目标,Observer是抽象的观察者,ConcreteSubject是具体的观察者
2.3观察者模式的实例及代码
比如在我们以前互联网不发达的时候,人们都需要订阅报纸来获取信息。我们可以假设每一次报纸出新的一期后,都需要通知订阅的用户前来取报纸。这个场景就是一个明显的观察者模式,每一期新出来的报纸是观察的目标,订阅的用户是观察者。

public interface ISubject {
    void attach(IObserver observer);
    void detach(IObserver observer);
    void notifyOberver();
}
public interface IObserver {
    void update();
}
public class ConcreteSubject implements ISubject {
    protected static final List<IObserver> obsevers = new LinkedList<IObserver>();
    private String state;

    @Override
    public void attach(IObserver observer) {
        obsevers.add(observer);
    }
    @Override
    public void detach(IObserver observer) {
        obsevers.remove(observer);
    }
    @Override
    public void notifyOberver() {
        for (IObserver observer : obsevers
        ) {
            observer.update();
        }
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
}
public class SubscribeOne implements  IObserver {
    private String name;
    public SubscribeOne(String name){
        this.name = name;
    }
    @Override
    public void update() {
        System.out.println("新的一期报纸已经更新,请"+name+"前来取报纸");
    }
}

2.4观察者模式的优缺点
-在观察目标和观察者之间建立了抽象的耦合,可以进行广播,符合“开闭原则”
-若一个观察目标有多个观察者的话,通知所有的观察者将会花费大量的时间;观察者只知道观察目标发生了变化,是怎样发生变化的观察者是不了解的

3、状态模式(State Pattern)

3.1状态模式定义
状态模式:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
3.2状态模式类结构图
状态模式结构图
3.3状态模式实例及代码
比如在我们的当代生活中,网上购物是我们生活中不可或缺的一部分。一网上购物流程可以有多种状态:浏览商品、下订单、卖家发货、物流公司运输、买家收货等多种状态,购物的状态不同对应的对货物的操作也不相同。
代码参加github
3.4状态模式优缺点
-封装了转换规则;将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
-状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。类的数量会大量的增加

4、迭代器模式(Iterator Pattern)

4.1迭代器模式定义
迭代器模式:提供一种方法顺序访问一个聚合对象中的各个对象,而不暴露该对象的内部表示。
4.2迭代器模式结构图
迭代器模式结构图
4.3迭代器模式实例及代码
在jdk中有好多都是使用迭代器模式来处理容器内部的数据访问问题的,具体的我们可以去参看集合框架中是怎么来使用迭代器的。
4.4迭代器模式优缺点
-它支持以不同的方式遍历一个聚合对象;在同一个聚合上可以有多个遍历;增加新的聚合类和迭代器类都很方便,无须修改原有代码。
-类的数量会增加,这增加了系统的复杂性

5、命令模式(Command Pattern)

5.1命令模式的定义
命令模式:将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。对发送者和接收者进行解耦,发送者与接收者之间没有直接的引用关系,发送请求的对象只知道如何发送请求而不用关心请求是如何完成的。
5.2命令模式的结构图
命令模式结构图
Command用来声明操作的接口;ConcreteCommand具体的命令类,将一个接收者绑定一个对象,调用接收者相应的动作;Receiver执行请求相关的动作;Invoker要求该命令执行该请求
5.3命令模式的实例及代码
在我们日常生活中去肯德基点餐这就是一个命令模式的具体应用,我们只需要将我们需要点的参告诉服务员,服务员将我们的请求命令发送给厨师,这里服务员就是一个命令类,而厨师就是命令 的接收者。

public abstract class Command {
    protected Kitchen receiver;
    public Command(Kitchen receiver){
        this.receiver = receiver;
    }
    public abstract void executorCommand();
}
public class Kitchen {
    public void makeChickenWings(){
        System.out.println("正在做鸡翅");
    }
    public void makeBurger(){
        System.out.println("正在做汉堡");
    }
}
public class Waiter {
    private List<Command> orders = new LinkedList<>();
    public void setOrders(Command command){
        orders.add(command);
    }
    public void cancelOrder(Command command){
        orders.remove(command);
    }
    //省略修改订单等操作
    public void notifyReceiver(){
        for (Command command : orders) {
            command.executorCommand();
        }
    }
}
//省略其他的命令的具体类

5.4命令模式的优缺点
-降低了系统的耦合度;可以方便的对命令进行撤销和恢复(与备忘录模式相结合);可以很容易的将新命令加入进来
-可能会导致系统有过多的命令类,导致类数量爆炸

6、责任链模式(Chain of Responsibility Pattern)

6.1责任链模式定义
责任链模式:使得多个对象都有机会来处理请求,从而避免了请求发送者与接收者之间的耦合关系。将这个对象形成一个链,并沿着链来传递请求,知道有一个对象处理它为止。
6.2责任链模式的结构图
责任链模式结构图
6.2责任链模式实例及代码
在我们生活中常常会遇到自己解决不了的事时,需要向上一级的部门汇报。我们假设这样一个场景,在大学生活中,班长能批准的假期最多只有1天;超过1天但是小于3天时需要得到辅导员的允许;超过3天但是没有超过一周需要院长来签字;超过一周你就只能呵呵(不给你准假)了。这里请假等级不断向上递增的过程就是一个责任链的实现,责任链的顶端就是不给你批假条。

public abstract class Handler {
    protected Handler handler;
    public void setHandler(Handler handler) {
        this.handler = handler;
    }
    public abstract void  handleRequest(double day);
}
public class SquadLeader extends Handler {
    @Override
    public void handleRequest(double day) {
        if (day < 1) {
            System.out.println("你的假期小于1天,班长批准的假期");
        } else {
            handler.handleRequest(day);
        }
    }
}
//此处省略辅导员和院长的,参考我的github

6.4责任链模式的优缺点
-系统的耦合度降低;可扩展性提高;责任链中的分工明确,每个环节只处理与自己相关的任务。
-请求有可能得不到处理;若请求链过长会影响系统的性能;责任链的建立需要客户端的参与

7、解释器模式(Interpreter Pattern)

7.1解释器模式定义
解释器模式:给定一个语言,定义它的一种文法表示,并定义一个解释器。这个解释器使用该表示来解释语言中的句子。文法指的是语法规则,而“句子”是语言集中的元素。其模式东急为:如果在系统中某一特定类型的问题发生的频率很高,此时可以考虑将这些问题的实例表述为一个语言中的句子,因此可以构建一个解释器,该解释器通过解释这些句子来解决这些问题。
7.2解释器模式的结构图
解释器模式结构图
7.3解释器模式实例及代码
现在我们假设这样一种场景,在乘坐高铁是出于对本地的老人和小孩没有收入来源的考虑,某一个地方的高铁站实行对老人和小孩免费乘车的政策,其余地方的老人和小孩是需要收费的。假设该地方所包含的区域有A,B,C这三个地方。其余地方的老人和小孩乘车时需要收费的。

public interface Expression {
    boolean interpret(String context);
}
public class TerminalExpression implements Expression {
    private Set<String> set = new HashSet<>();
    public TerminalExpression(String [] datas){
        for(String data : datas){
            set.add(data);
        }
    }
    @Override
    public boolean interpret(String context) {
        if(set.contains(context)){
            return true;
        }
        return false;
    }
}
public class NonTerminalExpression implements Expression {
    private Expression expressionOne,expressionTwo;
    public NonTerminalExpression(Expression expressionOne,Expression expressionTwo){
        this.expressionOne = expressionOne;
        this.expressionTwo = expressionTwo;
    }
    @Override
    public boolean interpret(String context) {
        String[] s = context.split("的");
        return expressionOne.interpret(s[0])&&expressionTwo.interpret(s[1]);
    }
}
public class Context {
    private String [] cities = {"A","B","C"};
    private String [] person = {"老人","儿童"};
    private NonTerminalExpression nonTerminal;
    public Context(){
        TerminalExpression terminalOne = new TerminalExpression(cities);
        TerminalExpression terminalTwo = new TerminalExpression(person);
        nonTerminal = new NonTerminalExpression(terminalOne,terminalTwo);

    }
    public void test(String info){
        boolean ok = nonTerminal.interpret(info);
        if(ok){
            System.out.println("您可以免费乘车");
        }else{
            System.out.println("您不可以免费乘车");
        }
    }
}

8.4解释器模式的优缺点
-扩展性好,由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法;容易实现,在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。
-执行效率低下;可以应用的场景比较少。

8、访问者模式(Visitor Pattern)

8.1访问者模式定义
访问者模式:表示一个作用于某对象结构中的各元素的操作。它使你在不改变各个元素类的前提下定义作用于这些元素的新操作。它作用的对象是数据结构相对稳定的系统,
8.2访问者模式结构图
访问者模式
8.3访问者模式实例及代码
还有顾客在商场购物时放在“购物车”中的商品,顾客主要关心所选商品的性价比,而收银员关心的是商品的价格和数量。这里商品就是一个元素,而顾客和收银员就是具体的访问者,而购物车则为对象结构用来容纳商品。这里为什么要说访问者模式针对的是数据结构相对稳定的系统呢,在我们的例子中一旦添加新的商品,就必须在访问者中去添加相应的vist方法,这样才能访问该商品,但这违背了OOP的“开闭原则”。

public interface Elements {
    void accept(Visitor visitor);
}
public interface Visitor {
    void visit(Cup cup); //定义访问者中,访问商品杯子的方法
    void visit(Computer computer);//定义访问者中,访问商品电脑的方法
}
/**
 * 具体的商品杯子,实现了Elmentse接口
 */
public class Cup implements Elements {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
//此处省略其他商品的信息
public class Customer implements Visitor {
    @Override
    public void visit(Cup cup) {
        System.out.println("我是顾客,我正在查看杯子的价格,我只关心杯子的性价比");
    }
    @Override
    public void visit(Computer computer) {
        System.out.println("我是顾客,我正在查看电脑的价格,我只关心电脑的性价比");
    }
}
//此处省略其他访问者

8.4访问者模式的优缺点
-将数据的结构与对数据的操作相分离,所以扩展新较好。符合OOP的“单一职责”原则。复用性好,通过访问者来定义整个结构上的功能,提高了系统的复用程度。
-系统比较复杂,较难理解;面向对象得分数据结构应该相对稳定,若不稳定就会由于添加新的元素而导致违背OOP中的“开闭原则”。
引用参考:
《大话设计模式》
https://designpatterns.readthedocs.io/zh_CN/latest/behavioral_patterns/strategy.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值