行为型设计模式:关注对象之间的通信方式,以及如何合作共同完成任务。这些模式涉及到对象之间的交互、责任分配等。
行为型设计模式共11种:策略设计模式,模板方法设计模式,观察者设计模式,责任链设计模式,访问者设计模式,中介者设计模式,迭代器设计模式,命令设计模式,状态设计模式,备忘录设计模式,解释器设计模式。
一、策略设计模式 英文名: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、痛点 把方法和所需的上下文信息单独提炼出来成为一个命令对象,适合场景有:
有属于同一个父类的N个子类,某个方法的实现本质只有P种,P远小于N,即存在很大的代码冗余,此时如果引入P个命令对象,即可消除代码冗余
提炼命令对象后,其扩展更加灵活,修改更加便捷,比如“可以支持撤销”,“方法的实现可以更加优化”
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 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 abstract class Parent { String getName () { return getClass().getSimpleName(); } abstract void execute () ; } class A0 extends Parent { @Override public void execute () { System.out.println(getName() + " Type A" ); } } class A1 extends Parent { @Override public void execute () { System.out.println(getName() + " Type A" ); } } class A2 extends Parent { @Override public void execute () { System.out.println(getName() + " Type A" ); } } class B0 extends Parent { @Override public void execute () { System.out.println(getName() + " Type B" ); } } class B1 extends Parent { @Override public void execute () { System.out.println(getName() + " Type B" ); } } class B2 extends Parent { @Override public void execute () { System.out.println(getName() + " Type B" ); } } class C0 extends Parent { @Override public void execute () { System.out.println(getName() + " Type C" ); } } class C1 extends Parent { @Override public void execute () { System.out.println(getName() + " Type C" ); } } class C2 extends Parent { @Override public void execute () { System.out.println(getName() + " Type C" ); } }
使用命令设计模式示例代码如下:
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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 interface Command { void execute () ; } abstract class Parent { Command command; public Parent (Command command) { this .command = command; } void execute () { command.execute(); } } class A0 extends Parent { public A0 (Command command) { super (command); } } class A1 extends Parent { public A1 (Command command) { super (command); } } class A2 extends Parent { public A2 (Command command) { super (command); } } class B0 extends Parent { public B0 (Command command) { super (command); } } class B1 extends Parent { public B1 (Command command) { super (command); } } class B2 extends Parent { public B2 (Command command) { super (command); } } class C0 extends Parent { public C0 (Command command) { super (command); } } class C1 extends Parent { public C1 (Command command) { super (command); } } class C2 extends Parent { public C2 (Command command) { super (command); } } class ACommand implements Command { @Override public void execute () { System.out.println("Type A" ); } } class BCommand implements Command { @Override public void execute () { System.out.println("Type B" ); } } class CCommand implements Command { @Override public void execute () { System.out.println("Type C" ); } } public class CommandPatternExample { public static void main (String[] args) { ACommand aCommand = new ACommand (); BCommand bCommand = new BCommand (); CCommand cCommand = new CCommand (); A0 a0 = new A0 (aCommand); A1 a1 = new A1 (aCommand); A2 a2 = new A2 (aCommand); B0 b0 = new B0 (bCommand); B1 b1 = new B1 (bCommand); B2 b2 = new B2 (bCommand); C0 c0 = new C0 (cCommand); C1 c1 = new C1 (cCommand); C2 c2 = new C2 (cCommand); a0.execute(); a1.execute(); a2.execute(); b0.execute(); b1.execute(); b2.execute(); c0.execute(); c1.execute(); c2.execute(); } }
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