设计模式之行为型

前言

最近加班是真的不少,没法腾出大块时间来学习。设计模式又不想只更到一半半途而废,想了又想,决定精简,保证你们一看就懂(看完就忘...)。设计模式分建立型模式,结构型模式和行为型模式。到目前为止,建立型模式已经讲完,对于剩下的模式,会分红这两大块统一讲解。算法

行为型模式

行为型模式主要关注的点事类的动做,各个类之间相互的做用,将职责划分清楚,使咱们的代码更加的清晰。数据库


策略模式

定义一组算法,将每一个算法都封装起来,而且使他们之间能够互换。
策略模式是一个出现频率很高,但又很简单的模式。下面的场景是咱们要出去旅游,可是能够选择出去旅游的交通方式,好比坐飞机,坐火车或者步行。废话再也不多说,直接上码:
public interface Strategy {
    void travel();
}
public class Walk implements Strategy {
    @Override
    public void travel() {
        System.out.println("步行去旅行");
    }
}
public class Train implements Strategy {
    @Override
    public void travel() {
        System.out.println("坐火车去旅行");
    }
}
public class Airplane implements Strategy {
    @Override
    public void travel() {
        System.out.println("坐着飞机去旅行");
    }
}
public class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    public void execute(){
        strategy.travel();
    }
}
public class Client {
    public static void main(String[] args) {
        Context context = new Context(new Airplane());
        context.execute();
    }
}
console:
坐着飞机去旅行

策略模式的优势很是明显,在现有的系统中增长一个策略太容易,只要实现接口就能够了,其余都不用修改,相似于一个能够反复拆卸的插件,符合ocp原则。其缺点就是每一个策略都是一个类,复用性很小,复杂的业务场景容易发生类数量爆炸,而且策略模式和迪米特法则是违背的,咱们看下上面的clent场景类(至关于项目中的高层调用模块),我只是想使用一个策略,凭什么就要了解这个策略呢?那要封装类就没有意义了,这是策略模式的一个大缺点,因此策略模式不多单独出现,大多结合其余模式来弥补这个缺陷,如工厂方法或者代理模式。segmentfault


观察者模式

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则全部依赖于它的对象都会获得通知并被自动更新

策略模式也叫发布订阅模式,其中最主要额角色名称就是subject被观察者和observer观察者。接下来会模拟一个场景,学校做为被观察者发布放假的消息,家长和学生做为观察者实现本身的逻辑:设计模式

/**
 * 主题(被观察者)须要实现的职责,就是能够动态的增长删除观察者。
 * 根据主题的状态通知全部的观察者Observer
 */
public abstract class Subject {
    private Vector<Observer> observerList = new Vector<>();

    private int status;

    public void addObserver(Observer observer){
        observerList.add(observer);
    }

    public void delObserver(Observer observer){
        observerList.remove(observer);
    }
    public void notifyAllObserver(){
        observerList.forEach(observer -> {
            observer.update();
        });
    }

}
public class SchoolSubject extends Subject {
    //学校宣布放七天假期
    public void haveSevenDaysHoliday(){
        System.out.println("学校:从今天开始放假,全部学生七天后返校");
        super.notifyAllObserver();
    }
}
public interface Observer {
    //观察者,被通知了实现其本身的逻辑
     void update() ;
}
public class Parent implements Observer {
    @Override
    public void update() {
        System.out.println("家长:这倒霉孩子怎么又放假了,坚定不能让他玩王者荣耀....");
    }
}
public class Student implements Observer {
    @Override
    public void update() {
        System.out.println("学生:哇哈哈,终于有时间打王者荣耀喽");
    }
}
public class Client {

    public static void main(String[] args) {
        SchoolSubject subject = new SchoolSubject();
        Student student = new Student();
        Parent parent = new Parent();
        subject.addObserver(student);
        subject.addObserver(parent);
        subject.haveSevenDaysHoliday();
    }

}
console:
学校:从今天开始放假,全部学生七天后返校
学生:哇哈哈,终于有时间打王者荣耀喽
家长:这倒霉孩子怎么又放假了,坚定不能让他玩王者荣耀....

虽然说观察者和被观察者是耦合在一块儿的,可是不论是扩展增长观察者仍是被观察者都很是容易。而且根据单一职责原则,每一个类的职责都是惟一,须要一套机制将类串联起来造成一个真实的场景,就好比学校公布放假,孩子想着玩游戏,家长为了孩子的成绩禁止孩子玩游戏,而后由于学校放假我就不玩了(小学生,你懂得),这样就造成了一个触发机制。其缺点就是执行效率低下,需异步执行。从原理上看,咱们经常使用的mq就是观察者模式的升级版。异步

责任链模式

使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

责任链咱们很容易想到链表结构,实际上责任链就是一种基于链表的处理方式。当一个请求过来,调用链表的头结点,处理以后再日后流转。
有这么一个场景:路飞饿了打开美团准备订外卖。选中吃的后,进行下单,首先校验是否在营业时间内,而后校验是否在配送范围内,而后校验是否有货等等,设定责任链都经过后,路飞才能订到饭。ide

//链表内结点的基类
public abstract class RuleHandler {

    protected RuleHandler successor;

    public abstract void echo(Context context);

    public void setSuccessor(RuleHandler successor) {
        this.successor = successor;
    }

    public RuleHandler getSuccessor() {
        return successor;
    }
}
//判断营业时间
public class TimeHandler extends RuleHandler {
    @Override
    public void echo(Context context) {
        //营业时间判断
        if (context.isTimeInRange()){
            if (this.getSuccessor()!=null){
                this.getSuccessor().echo(context);
            }
        }else {
            throw new RuntimeException("不在营业时间内");
        }
    }
}
//判断是否在配送范围内
public class AreaHanler extends RuleHandler {
    @Override
    public void echo(Context context) {
        if (context.isAreaInRange()){
            if (this.getSuccessor()!=null){
                this.getSuccessor().echo(context);
            }
        }else {
            throw  new RuntimeException("不在配送范围内");
        }
    }
}
//判断库存
public class StockHandler extends RuleHandler {
    @Override
    public void echo(Context context) {
        if (context.hasStock()){
            if (this.getSuccessor()!=null){
                this.getSuccessor().echo(context);
            }
        }else {
            throw new RuntimeException("挑选的商品已经卖完");
        }
    }
}

客户端调用逻辑:性能

public class Client {

    public static void main(String[] args) {
        RuleHandler timeHandler = new TimeHandler();
        RuleHandler areaHandler = new AreaHanler();
        RuleHandler stockHandler = new StockHandler();
        
        timeHandler.setSuccessor(areaHandler);
        areaHandler.setSuccessor(stockHandler);
        timeHandler.echo(new Context());
    }
    
}

代码很是简单,责任链模式的重点是在链上,由一条链去处理请求并返回相应的结果。它很是显著的优势就是将请求和处理分开,二者解耦,提升系统的灵活性。缺点就是链表遍历必须从链头到链尾,存在性能问题。采用了相似递归调用的方式,增大了读懂逻辑的难度学习

模板方法模式

在以前的博客里已经长篇大论过,故直接拿过来。
模板方法测试

状态模式

当一个对象内在状态改变时容许其改变行为,这个对象看起来像改变了其类。

状态模式的核心是封装,经过状态的变动引发行为的变动。如今你们来思考一下,电脑有三种状态,分别为关机,已启动。this

//表明环境,也就是状态的主体
public class Context {

    //全部的电脑状态
    public final static OpenState OPEN = new OpenState();
    public final static CloseState CLOSE = new CloseState();
    //电脑当前的状态
    private ComputerState currentState;

    public ComputerState getCurrentState() {
        return currentState;
    }

    public void setCurrentState(ComputerState currentState) {
        this.currentState = currentState;
        this.currentState.setContext(this);
    }

    public void openMachine() {
        this.currentState.openMachine();
    }

    public void closeMachine() {
        this.currentState.closeMachine();
    }
}
//状态基类,真实的电脑逻辑封装在了状态中
public abstract class ComputerState {

    protected Context context;

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

    public abstract void closeMachine();

}
public class OpenState extends ComputerState{
    @Override
    public void openMachine() {
        System.out.println("电脑开机...");
    }

    @Override
    public void closeMachine() {
        super.context.setCurrentState(Context.CLOSE);
        super.context.getCurrentState().closeMachine();
    }
}
public class CloseState extends ComputerState {
    @Override
    public void openMachine() {
        super.context.setCurrentState(Context.OPEN);
        super.context.getCurrentState().openMachine();
    }

    @Override
    public void closeMachine() {
        System.out.println("电脑关机...");
    }
}

客户端测试类:

public class Client {
    public static void main(String[] args) {
        Context context = new Context();
        context.setCurrentState(Context.OPEN);
        context.openMachine();
        context.closeMachine();
    }
}

状态模式的优势有结构清晰,避免了各类条件的判断,省掉了swtich...case,if...else语句的使用,提高了代码的可读性。遵循了单一职责原则和开闭原则,每一个状态都是一个子类,增长状态只需增长一个状态子类,修改状态,修改对应的子类就能够了。封装性很是好,客户端不需知道内部状态的转换以及相应的逻辑.其缺点就是状态子类会太多,而且咱们能够将状态存储到数据库中,而后根据状态执行相应的操做,这也是一种不错的实现方式,具体如何使用看你们我的喜爱了。

总结

本章的行为型模式总结了策略模式、观察者模式、责任链模式、模板方法模式和状态模式,其实不只于此,还有备忘录模式和命令模式等,但因其使用场景有限,就不作一一探讨了,留给读者本身学习~.~

相关文章
相关标签/搜索