行为型设计模式:关注对象之间的通信方式,以及如何合作共同完成任务。这些模式涉及到对象之间的交互、责任分配等。
行为型设计模式共11种:策略设计模式,模板方法设计模式,观察者设计模式,责任链设计模式,访问者设计模式,中介者设计模式,迭代器设计模式,命令设计模式,状态设计模式,备忘录设计模式,解释器设计模式。 助记:
模板、策略
3个者——观察者、访问者、中介者
2个器——迭代器、解释器
责任链、备忘录
命令、状态
一、策略设计模式 英文名:Strategy Pattern。
1.1、痛点 实现一个方法A(实例方法/静态方法)时,其中某个方法过程具有多种变化,提炼该方法过程为一个接口B下的方法C,方法A实现中通过接口B调用方法C,后续提供B的具体实现子类(其中具体实现方法C)。在该场景中,接口B被称为策略接口 。
须注意 :以上接口B下的方法C,不必需是抽象的,可以是有实现的,后续覆盖即可。
1.2、实现 示例代码如下[1]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 interface MathOperation { int operate (int a, int b) ; } class Addition implements MathOperation { @Override public int operate (int a, int b) { return a + b; } } class Subtraction implements MathOperation { @Override public int operate (int a, int b) { return a - b; } } class Multiplication implements MathOperation { @Override public int operate (int a, int b) { return a * b; } } class Calculator { private MathOperation operation; public void setOperation (MathOperation operation) { this .operation = operation; } public int performOperation (int a, int b) { if (operation != null ) { return operation.operate(a, b); } throw new IllegalStateException ("No operation set" ); } } public class StrategyPatternExample { public static void main (String[] args) { Calculator calculator = new Calculator (); calculator.setOperation(new Addition ()); int result1 = calculator.performOperation(5 , 3 ); System.out.println("Addition Result: " + result1); calculator.setOperation(new Subtraction ()); int result2 = calculator.performOperation(10 , 4 ); System.out.println("Subtraction Result: " + result2); calculator.setOperation(new Multiplication ()); int result3 = calculator.performOperation(6 , 2 ); System.out.println("Multiplication Result: " + result3); } }
1.3、JDK中的例子
java.util.List
类的sort(Comparator<? super E> c)
方法实现使用了策略设计模式,其中策略接口是java.util.Comparator
java.util.Collections
类的sort(java.util.List<T>, java.util.Comparator<? super T>)
方法实现使用了策略设计模式,其中策略接口是java.util.Comparator
java.util.Arrays
类的sort(T[], java.util.Comparator<? super T>)
方法实现使用了策略设计模式,其中策略接口是java.util.Comparator
二、模板方法设计模式 英文名:Template Method Pattern。
2.1、痛点 在实现类C的实例方法a时,其中某个方法过程具有多种变化,提炼该方法过程为一个方法b,方法a实现中调用方法b,类C的具体实现子类中具体实现方法b。在该场景中,类C被称为模板方法类,方法a被称为模板方法 。
须注意 :以上方法b不必需是抽象的,可以是有实现的,后续覆盖即可。
2.2、实现 示例代码如下[1]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 abstract class AbstractClass { public void templateMethod () { step1(); step2(); step3(); } abstract void step1 () ; abstract void step2 () ; abstract void step3 () ; } class ConcreteClass extends AbstractClass { @Override void step1 () { System.out.println("ConcreteClass: Step 1" ); } @Override void step2 () { System.out.println("ConcreteClass: Step 2" ); } @Override void step3 () { System.out.println("ConcreteClass: Step 3" ); } } public class TemplateMethodPatternExample { public static void main (String[] args) { AbstractClass template = new ConcreteClass (); template.templateMethod(); } }
2.3、JDK中的例子
java.io.InputStream#read(byte[], int, int)
java.io.OutputStream#write(byte[], int, int)
java.io.Reader#read(java.nio.CharBuffer)
java.io.Writer#write(int)
java.io.Writer#write(java.lang.String, int, int)
java.io.InputStream#skip
三、观察者设计模式 英文名:Observer Pattern。
又被称为“发布订阅设计模式”。
3.1、痛点 实现需求:当作为观察目标的对象发生变化事件,对该变化事件感兴趣的作为观察者的对象能够得到通知。
3.2、实现 示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import java.util.ArrayList;import java.util.List;class Subscriber { public void onPublish () { System.out.println(this .hashCode() + ", 监听到发生的publish事件" ); } } class Publisher { List<Subscriber> subscriberList = new ArrayList <Subscriber>(); public void register (Subscriber subscriber) { subscriberList.add(subscriber); } public void publish () { for (Subscriber subscriber : subscriberList) { subscriber.onPublish(); } } } public class ObserverPatternExample { public static void main (String[] args) { Publisher publisher = new Publisher (); Subscriber subscriber0 = new Subscriber (); Subscriber subscriber1 = new Subscriber (); Subscriber subscriber2 = new Subscriber (); publisher.register(subscriber0); publisher.register(subscriber1); publisher.register(subscriber2); publisher.publish(); } }
3.3、JDK中的例子
java.util.Observable
作为观察目标,其相应的观察者为java.util.Observer
四、责任链设计模式 英文名:Chain of Responsibility Pattern。
4.1、痛点 实现需求:在接收到一个请求后,将请求的处理递交给一个处理链,解耦请求的接收和处理,后续便于请求处理逻辑的扩展。
4.2、实现 示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.util.ArrayList;import java.util.List;interface Request {} class Processor { public void process (Request request) { } } class Receiver { List<Processor> processorList = new ArrayList <>(); public void register (List<Processor> processorList) { this .processorList = processorList; } public void onReceive (Request request) { for (Processor processor : processorList) { processor.process(request); } } } public class ChainOfResponsibilityPatternExample {}
4.3、JDK中的例子
java.util.logging.Logger
类的public void log(LogRecord record)
方法中注释语句// Post the LogRecord to all our Handlers, and then to our parents' handlers, all the way up the tree
所展示的责任链设计模式应用
五、访问者设计模式 英文名:Visitor Pattern。
5.1、痛点 在面向对象编程中,一般情况下,字段和操作在一起。但是在有些场景中,后续不便于扩展增加操作,比如“类在第三方JAR包中”。针对这种情形,可采用访问者设计模式,它的核心思想是:引入一个称为“访问者”的接口或类,原欲扩展操作的类被称为元素类,在元素类中统一增加一个访问方法,该方法传入访问者实例,并将元素类实例本身传递给该访问者实例,在访问者方法实现中完成对传入元素类实例的访问操作。
5.2、实现 一般情况下,字段和操作在一起,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 interface Shape { double getArea () ; } class Circle implements Shape { private double radius; public Circle (double radius) { this .radius = radius; } @Override public double getArea () { return Math.PI * radius * radius; } } class Rectangle implements Shape { private double width; private double height; public Rectangle (double width, double height) { this .width = width; this .height = height; } @Override public double getArea () { return width * height; } } public class NormalObjectOrientedProgramming {}
当不便于增加新的操作时,可以采用访问者设计模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 interface Shape { void accept (ShapeVisitor visitor) ; } interface ShapeVisitor { void visit (Circle circle) ; void visit (Rectangle rectangle) ; } class Circle implements Shape { private double radius; public Circle (double radius) { this .radius = radius; } public double getRadius () { return radius; } @Override public void accept (ShapeVisitor visitor) { visitor.visit(this ); } } class Rectangle implements Shape { private double width; private double height; public Rectangle (double width, double height) { this .width = width; this .height = height; } public double getWidth () { return width; } public double getHeight () { return height; } @Override public void accept (ShapeVisitor visitor) { visitor.visit(this ); } } class AreaCalculator implements ShapeVisitor { @Override public void visit (Circle circle) { System.out.println("circle area is: " + Math.PI * circle.getRadius() * circle.getRadius()); } @Override public void visit (Rectangle rectangle) { System.out.println("rectangle area is: " + rectangle.getWidth() * rectangle.getHeight()); } } public class VisitorPatternExample { public static void main (String[] args) { Circle circle = new Circle (5 ); Rectangle rectangle = new Rectangle (4 , 6 ); AreaCalculator areaCalculator = new AreaCalculator (); circle.accept(areaCalculator); rectangle.accept(areaCalculator); } }
5.3、JDK中的例子
java.nio.file.Files
类public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)
方法中涉及到访问者设计模式的应用
六、中介者设计模式 英文名:Mediator Pattern。
6.1、痛点 类A和类B原本直接联系,现引入一个类C,类A和类B通过类C进行联系,如此类A和类B的独立性得以增强。在该场景中,类C被称为中介者 。
6.2、实现 直接联系示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class TalkPeerA { TalkPeerB talkPeerB; public void receive (String message) { System.out.println(message); } public void send () { talkPeerB.receive("A message" ); } public void setTalkPeerB (TalkPeerB talkPeerB) { this .talkPeerB = talkPeerB; } } class TalkPeerB { TalkPeerA talkPeerA; public void send () { talkPeerA.receive("B message" ); } public void receive (String message) { System.out.println(message); } public void setTalkPeerA (TalkPeerA talkPeerA) { this .talkPeerA = talkPeerA; } } public class CommunicateDirectExample { public static void main (String[] args) { TalkPeerA talkPeerA = new TalkPeerA (); TalkPeerB talkPeerB = new TalkPeerB (); talkPeerB.setTalkPeerA(talkPeerA); talkPeerA.setTalkPeerB(talkPeerB); talkPeerA.send(); talkPeerB.send(); } }
使用中介者设计模式示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 import java.util.Queue;import java.util.concurrent.LinkedBlockingDeque;class TalkPeerA { Queue<String> sendQueue; Queue<String> receiveQueue; public TalkPeerA (Queue<String> sendQueue, Queue<String> receiveQueue) { this .sendQueue = sendQueue; this .receiveQueue = receiveQueue; } public void receive () { while (!receiveQueue.isEmpty()) { System.out.println(receiveQueue.poll()); } } public void send () { sendQueue.add("sender A message" ); } } class TalkPeerB { Queue<String> sendQueue; Queue<String> receiveQueue; public TalkPeerB (Queue<String> sendQueue, Queue<String> receiveQueue) { this .sendQueue = sendQueue; this .receiveQueue = receiveQueue; } public void send () { sendQueue.add("sender B message" ); } public void receive () { while (!receiveQueue.isEmpty()) { System.out.println(receiveQueue.poll()); } } } public class MediatorPatternExample { public static void main (String[] args) { Queue<String> aToB = new LinkedBlockingDeque <>(); Queue<String> bToA = new LinkedBlockingDeque <>(); TalkPeerA talkPeerA = new TalkPeerA (aToB, bToA); TalkPeerB talkPeerB = new TalkPeerB (bToA, aToB); talkPeerA.send(); talkPeerB.send(); talkPeerA.receive(); talkPeerB.receive(); } }
6.3、JDK中的例子
java.util.Timer
类使用了中介者设计模式,具体是引入了中介者private final TaskQueue queue = new TaskQueue()
七、迭代器设计模式 英文名:Iterator Pattern。
7.1、痛点 提供一种方法来遍历容器对象中的各个元素,而无需暴露该对象的内部细节。
7.2、实现 见“7.3、JDK中的例子”小节内容。
7.3、JDK中的例子
java.util.Iterator
是一个迭代器接口,容器对象实例a可返回一个跟a关联的java.util.Iterator
接口具体实现子类实例对象b,外界通过b可遍历访问a,比如“java.util.ArrayList
类中public Iterator<E> iterator()
方法所示”
java.util.Enumeration
是一个迭代器接口,容器对象实例a可返回一个跟a关联的java.util.Enumeration
接口具体实现子类实例对象b,外界通过b可遍历访问a,比如“java.util.Collections
类中public static <T> Enumeration<T> enumeration(final Collection<T> c)
方法所示”
八、命令设计模式 英文名:Command Pattern。
8.1、痛点 提供了将操作封装成对象(命令对象)的方法,使得操作的发送者与接收者之间不直接耦合,从而使得后续扩展更加灵活,修改更加便捷,比如“可以支持操作排队、记录、撤销或者重做”。
8.2、实现 现有一个业务场景:遥控器控制电灯开关。
不使用命令模式,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Light { void turnOn () { System.out.println("Light is on" ); } void turnOff () { System.out.println("Light is off" ); } } class RemoteControl { private Light light; public RemoteControl (Light light) { this .light = light; } public void turnOnLight () { light.turnOn(); } public void turnOffLight () { light.turnOff(); } } public class DirectOpExample { public static void main (String[] args) { Light livingRoomLight = new Light (); RemoteControl remote = new RemoteControl (livingRoomLight); remote.turnOnLight(); remote.turnOffLight(); } }
使用命令设计模式——遥控器作为命令发送者触发命令的执行,电灯作为命令接收者执行实际的开关操作,封装了原本遥控器对电灯的直接操作为命令对象
,示例代码如下[1]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 interface Command { void execute () ; } class LightOnCommand implements Command { private Light light; public LightOnCommand (Light light) { this .light = light; } @Override public void execute () { light.turnOn(); } } class LightOffCommand implements Command { private Light light; public LightOffCommand (Light light) { this .light = light; } @Override public void execute () { light.turnOff(); } } class Light { void turnOn () { System.out.println("Light is on" ); } void turnOff () { System.out.println("Light is off" ); } } class RemoteControl { private Command command; public void setCommand (Command command) { this .command = command; } public void pressButton () { command.execute(); } } public class CommandPatternExample { public static void main (String[] args) { Light livingRoomLight = new Light (); LightOnCommand livingRoomLightOn = new LightOnCommand (livingRoomLight); LightOffCommand livingRoomLightOff = new LightOffCommand (livingRoomLight); RemoteControl remote = new RemoteControl (); remote.setCommand(livingRoomLightOn); remote.pressButton(); remote.setCommand(livingRoomLightOff); remote.pressButton(); } }
8.3、JDK中的例子
java.lang.Runnable
是命令对象接口
九、状态设计模式 英文名:State Pattern。
又称“状态机设计模式”。
9.1、痛点 当一个对象的行为跟所处状态紧密相关,那么可以采用状态设计模式,否则代码变得复杂且难以维护。
9.2、实现 示例代码如下[1]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 interface ElevatorState { void openDoors () ; void closeDoors () ; void move () ; void stop () ; } class OpenState implements ElevatorState { @Override public void openDoors () { System.out.println("Doors are already open." ); } @Override public void closeDoors () { System.out.println("Closing doors." ); } @Override public void move () { System.out.println("Cannot move while doors are open." ); } @Override public void stop () { System.out.println("Stopping while doors are open." ); } } class CloseState implements ElevatorState { @Override public void openDoors () { System.out.println("Opening doors." ); } @Override public void closeDoors () { System.out.println("Doors are already closed." ); } @Override public void move () { System.out.println("Moving." ); } @Override public void stop () { System.out.println("Stopping." ); } } class Elevator { private ElevatorState state; public Elevator () { state = new CloseState (); } public void openDoors () { if (state instanceof OpenState) { state.openDoors(); } else { state.openDoors(); state = new OpenState (); } } public void closeDoors () { if (state instanceof OpenState) { state.closeDoors(); state = new CloseState (); } else { state.closeDoors(); } } public void move () { state.move(); } public void stop () { state.stop(); } } public class StatePatternExample { public static void main (String[] args) { Elevator elevator = new Elevator (); elevator.move(); elevator.stop(); elevator.closeDoors(); elevator.openDoors(); elevator.move(); elevator.stop(); elevator.openDoors(); elevator.closeDoors(); } }
9.3、JDK中的例子 无。
十、备忘录设计模式 英文名:Memento Pattern。
10.1、痛点 引入备忘录类,保存目标对象的内部状态,后续可以借此恢复目标对象的内部状态。
10.2、实现 示例代码如下[1]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class Memento { private String state; public Memento (String state) { this .state = state; } public String getState () { return state; } } class Originator { private String state; public String getState () { return state; } public void setState (String state) { this .state = state; } public Memento createMemento () { return new Memento (state); } public void restoreMemento (Memento memento) { state = memento.getState(); } } public class MementoPatternExample { public static void main (String[] args) { Originator originator = new Originator (); originator.setState("State 1" ); System.out.println("Current State: " + originator.getState()); Memento memento = originator.createMemento(); originator.setState("State 2" ); System.out.println("Updated State: " + originator.getState()); originator.restoreMemento(memento); System.out.println("Restored State: " + originator.getState()); } }
10.3、JDK中的例子 无。
十一、解释器设计模式 英文名:Interpreter Pattern。
11.1、痛点 对一个领域特定语言(DSL)和其对应的表达式进行编程映射最好的形式就是采用解释器设计模式。
11.2、实现 示例代码如下[1]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 interface Expression { int interpret () ; } class NumberExpression implements Expression { private int value; public NumberExpression (int value) { this .value = value; } @Override public int interpret () { return value; } } class AddExpression implements Expression { private Expression leftOperand; private Expression rightOperand; public AddExpression (Expression leftOperand, Expression rightOperand) { this .leftOperand = leftOperand; this .rightOperand = rightOperand; } @Override public int interpret () { return leftOperand.interpret() + rightOperand.interpret(); } } class SubtractExpression implements Expression { private Expression leftOperand; private Expression rightOperand; public SubtractExpression (Expression leftOperand, Expression rightOperand) { this .leftOperand = leftOperand; this .rightOperand = rightOperand; } @Override public int interpret () { return leftOperand.interpret() - rightOperand.interpret(); } } public class InterpreterPatternExample { public static void main (String[] args) { Expression expression = new AddExpression ( new NumberExpression (2 ), new SubtractExpression ( new NumberExpression (3 ), new NumberExpression (1 ) ) ); int result = expression.interpret(); System.out.println("Result: " + result); } }
11.3、JDK中的例子
java.util.Pattern
类使用了解释器设计模式
参考文献 [1]https://mp.weixin.qq.com/s/H16g_yZwRMIKagPb8oNIYQ