GOF 23设计模式之(行为型模式一)
Posted huangcan1688
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GOF 23设计模式之(行为型模式一)相关的知识,希望对你有一定的参考价值。
目录
1.模板方法模式
2.策略模式
3.命令模式
4.职责链模式
5.状态模式
6.观察者模式
一、模板方法模式(Template Method)
定义操作中的算法骨架,将某些步骤延迟到子类中实现。这样,新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。即:处理步骤父类中定义好,具体实现延迟到子类中定义。
核心角色:
(1)抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。定义如下:
1、模板方法:定义算法骨架,按某个顺序调用其包含的基本方法。
2、基本方法:是整个方法的一个步骤,包含有:
抽象方法:在抽象类中声明,由具体类实现。
具体方法:在抽象类中已经实现,可以在子类中继承或重写它
钩子方法:在抽象类已经实现,包括判断逻辑方法和需要子类重写的空方法两种。
(2)具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,是一个顶级逻辑的一个组成步骤。
优点:
(1)封装了不变部分在父类中实现,变的部分在子类中实现,便于子类的继续扩展。
(2)在父类中提取了公共部分代码,便于代码的复用。
(3)部分方法是在子类实现的,子类可以扩展增加相应的功能,符号开闭原则。
缺点:
(1)对每一个不同的实现都需要定义子类,导致类的数量增加,设计也更抽象。
(2)父类的抽象方法由子类实现,子类执行的结构会影响父类的结果,导致了一种反向的控制结构,提高了代码阅读的难度。
public class textTemplateMethod { public static void main(String[] args) { // TODO Auto-generated method stub //模拟一个排队打饭的场景。 //前面两个步骤:排队、打饭、是每一个人都要做的。可以建立为模板 //吃饭和各自洗盘子。是扩展完成的 AbstractClass tm = new ConcreteClass(); tm.TemplateMethod(); } } //抽象类 abstract class AbstractClass{ public void TemplateMethod() { //模板方法 SpecificMethod(); abstractMethod1(); abstractMethod2(); } public void SpecificMethod() { //具体方法 System.out.println("排队"); System.out.println("打饭"); } public abstract void abstractMethod1(); //抽象方法1 public abstract void abstractMethod2(); //抽象方法1 } //具体子类 class ConcreteClass extends AbstractClass{ @Override public void abstractMethod1() { System.out.println("各自找位置吃饭"); } @Override public void abstractMethod2() { System.out.println("各自洗各自的盘子"); } }
二、策略模式(Strategy)
定义了一系列的算法,并将每个算封装起来成为一个算法族。允许用户从算法族中任选一个算法解决某问题,且算法的变化不会影响使用算法的客户,使算法的责任和算法的实现分隔开,并委派给不同的对象对这些算法进行管理。
核心角色:
(1)抽象策略类(Strategy):定义一个公共接口,不同的算法以不同的方法区实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
(2)具体策略类(Concrete Strategy):实现了抽象策略定义的接口。提供具体的算法实现。
(3)环境类(Context):只有一个策略类的引用,最终给客户端调用。
优点:
(1)多重条件语句不易维护,使用策略模式可以避免使用多重条件语句。
(2)可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的策略。
(3)提供了对开闭原则的完美支持,不修改原代码的情况下,灵活增加新算法。
(4)将算法的使用放在环境中,算法的实现移到具体的策略中。实现了二者分离。
缺点:
(1)客户端必须理解所有的策略算法区别,以便适时选择恰当的算法类。
(2)策略模式造成很多策略类。
public class textTemplateMethod { public static void main(String[] args) { // TODO Auto-generated method stub //模拟一个做菜。像龙虾的做法有很多。举椒盐、清蒸的方法。 Context cf = new Context();//创建厨房 Strategy lx = new ConcreteStrategyA();//椒盐龙虾做法 cf.setStrategy(lx);//厨房做菜 cf.strategyMethod();//炒出来的菜 } } //抽象策略类 (龙虾加工类) interface Strategy{ public void strategyMethod();//策略方法 (做菜的方法) } //具体策略类A class ConcreteStrategyA implements Strategy{ @Override public void strategyMethod() { System.out.println("椒盐龙虾"); } } //具体策略类B class ConcreteStrategyB implements Strategy{ @Override public void strategyMethod() { System.out.println("清蒸龙虾"); } } //环境类 (厨房) class Context{ private Strategy strategy; public Strategy getStrategy() { return strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } public void strategyMethod() { strategy.strategyMethod(); //做菜 } }
三、命令模式(Command)
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分离开。两者通过命令来沟通。方便将命令对象进行存储、传递、调用、增加与管理。
核心角色:
(1)抽象命令类角色(Command):声明执行命令的接口,拥有执行命令的抽象方法execute().
(2)具体命令角色(Concrete Command):实现抽象命令类,拥有接收者对象,并且调用接收者的功能来完成命令要执行的操作。
(3)实现者/接收者角色(Receiver):执行命令功能的相关操作,是具体命令对象业务的真正实现者。
(4)调用者/请求者角色(Invoker):是请求的发送者,通过拥有很多的命令对象和访问命令对象来执行相关的请求,它不直接访问接收者。
优点:
(1)降低了系统的耦合度。能将调用操作的对象与实现该操作的对象解耦。
(2)增加或删除命令非常方便。增加和删除不会影响其他类,满足开原则。
(3)可以实现宏命令。可以与组合模式结合,将多个命令装配成一组命令(宏命令)
(4)方便实现Undo、Redo操作。与备忘录模式结合,实现命令的撤销和恢复。
缺点:
(1)可能产生大量具体命令类。每一个具体操作都需要设计一个具体命令类。增加了系统复杂性。
public class textCommand { public static void main(String[] args) { // TODO Auto-generated method stub //模拟客户去餐厅吃饭。客户向服务员下达命令,然后。服务员向厨师下达命令,最后上菜 //这里与吃肠粉为例 Command command = new ConcreteCommand();//先是客户点了肠粉 Invoker fuy = new Invoker(command);//向服务员下达命令 fuy.call(); //厨师做出肠粉 } } //调用者 (服务员) class Invoker{ private Command command; public Invoker(Command command) { this.command = command; } public void setCommand(Command command) { this.command = command; } public void call() { command.exectue();//调用者执行命令 } } //抽象命令 (早餐) interface Command{ public abstract void exectue(); } //具体命令 (肠粉) class ConcreteCommand implements Command{ private Receiver receiver; ConcreteCommand(){ receiver = new Receiver(); //创建做肠粉的厨师 } @Override public void exectue() { receiver.action(); } } //接收者 (做肠粉的厨师) class Receiver{ public void action() {//接收者方法 System.out.println("做肠粉"); } }
四、职责链模式(Chain of Responsibility)
能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递链上的对象逐个判断是否有能力处理该请求,如果能则处理。反之,把请求传递给下一个对象。
核心角色:
(1)抽象处理者角色(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
(2)具体处理者角色(Concrete Handler):实现抽象处理者的方法,判断能否处理本次请求。如果能则处理。反之,将请求转给它的后继者。
(3)客户类角色(Client):创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
优点:
(1)降低了对象之间的耦合度。发送者和接收者无须拥有对方的明确信息。
(2)增强了系统的可扩展性。可以根据需要增加需要处理的类,满足开闭原则。
(3)增强了给对象指派职责的灵活性。当工作流程发生变化时,可以动态地改变链内的成员或调动他们的次序,也可以动态地新增或者删除责任。
(4)职责链简化了对象之间的连接。每个对象只要保持指向后继的引用。避免了if..else
(5)责任分担。每个类只需要处理自己该处理的工作。符合单一职责原则。
缺点:
(1)不能保证每一个请求一定被处理。可能一直传到末端都不能处理。
(2)对比较长的职责链,请求的处理可能涉及过个对象,系统性能将受一定的影响。
(3)职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性。
public class textCommand { public static void main(String[] args) { // TODO Auto-generated method stub //模拟一个请假的情况, //如果请假是两天以内的,班主任可以批假。超过了两天,7天以内,就要系主任批假 Handler bzr = new ConcreteHandlerA();//班主任 Handler xzr = new ConcreteHandlerB();//系主任 bzr.setNext(xzr);//班主任到系主任 bzr.handleRequest(5);//5天,班主任处理不了。推给系主任处理 } } //抽象者处理者 abstract class Handler{ private Handler next; public Handler getNext() { return next; } public void setNext(Handler next) { this.next = next; } public abstract void handleRequest(int request); } //具体处理者A class ConcreteHandlerA extends Handler{ @Override public void handleRequest(int request) { if(request <= 2) { System.out.println("班主任批准你请<"+request+">天假"); }else { if(getNext() != null) { //推给下一个继后者 getNext().handleRequest(request); }else { System.out.println("请假的天数太多,不能批假,请找主任。"); } } } } //具体处理者B class ConcreteHandlerB extends Handler{ @Override public void handleRequest(int request) { if(request <= 7) { System.out.println("系主任批准你请<"+request+">天假"); }else { if(getNext() != null) { //推给下一个继后者 getNext().handleRequest(request); }else { System.out.println("请假的天数太多,不能批假"); } } } }
五、状态模式(State)
解决系统中复杂的状态转换和不同状态行为的封装问题。把复杂的判断逻辑提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
核心角色:
(1)环境角色(Context):称为上下文。定义客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
(2)抽象状态角色(State):定义一个接口,用于封装环境对象中待定状态所对应的行为。
(3)具体状态角色(Concrete State):实现抽象状态所对应的行为。
优点:
(1)将特定状态相关的行为局部化到一个状态中,并将不同状态的行为分割开,满足单一职责原则。
(2)减少对象间的互相依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确。
(3)有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
缺点:
(1)使用必然会增加系统的类与对象的个数。
(2)其结构与实现都比较复杂。
public class textCommand { public static void main(String[] args) { // TODO Auto-generated method stub Context context = new Context(); context.Handle(); context.Handle(); context.Handle(); } } //环境类 class Context{ private State state; public Context() { //定义环境类的初始状态 this.state = new ConcreteStateA(); } //设置新的状态 public void setState(State state) { this.state = state; } //读取状态 public State getState() { return state; } //对请求做处理 public void Handle() { state.Handle(this); } } //抽象状态类 abstract class State{ public abstract void Handle(Context context); } //具体状态类A class ConcreteStateA extends State{ @Override public void Handle(Context context) { System.out.println("当前状态A"); context.setState(new ConcreteStateB()); } } //具体状态类B class ConcreteStateB extends State{ @Override public void Handle(Context context) { System.out.println("当前状态B"); context.setState(new ConcreteStateA()); } }
六、观察者模式
指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式又称为发布-订阅模式、模型-视图模式。
核心角色:
(1)抽象主题角色(Subject):也叫抽象目标类,一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
(2)具体主题角色(Concrete Subject):也叫具体目标类,实现抽象目标中的方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
(3)抽象观察者角色(Observer):是一个抽象类或者接口。包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
(4)具体观察者角色(Concrete Observer):实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
优点:
(1)降低目标与观察者之间的耦合关系,两者之间是抽象耦合。
(2)目标观察者时间建立了一套触发机制。
缺点:
(1)目标与观察者的依赖关系没有完全解除,而且可能出现循环引用。
(2)当观察者对象很多时,通知发布会花很多时间,影响程序的效率。
public class textCommand { public static void main(String[] args) { // TODO Auto-generated method stub //模拟电台与收音机。 //如果电台中换了播放的节目。那所有真再收听的收音机也会对应变化。 Subject dt = new ConcreteSubject();//电台节目 Observer syA = new ConcreteObserverA();//创建收音设备 Observer syB = new ConcreteObserverB(); dt.add(syA); //正在收音的设备 dt.add(syB); //原来播放的节目 dt.notifyObserver("乡村爱情故事"); System.out.println("-------------"); //电台改变节目 dt.notifyObserver("王牌对王牌"); } } //抽象目标 (电台) abstract class Subject{ protected List<Observer> observers = new ArrayList<Observer>(); //增加观察者方法 public void add(Observer observer) { observers.add(observer); } //删除观察者方法 public void remove(Observer observer) { observers.remove(observer); } //通知观察者方法 public abstract void notifyObserver(String show);//设置一个参数 } //具体目标 (节目) class ConcreteSubject extends Subject{ @Override public void notifyObserver(String show) { System.out.println("电台播放<"+show+">节目"); for (Observer obs : observers) { ((Observer)obs).response(show); } } } //抽象观察者 (收音设备) interface Observer{ void response(String show);//定义一个参数 } //具体观察者A (收音机A) class ConcreteObserverA implements Observer{ @Override public void response(String show) { System.out.println("收音机A正在播放<"+show+">节目"); } } //具体观察者B(收音机A) class ConcreteObserverB implements Observer{ @Override public void response(String show) { System.out.println("收音机A正在播放<"+show+">节目"); } }
以上是关于GOF 23设计模式之(行为型模式一)的主要内容,如果未能解决你的问题,请参考以下文章