文章目录
- 行为型模式(Behavioral Pattern)
- 1. 观察者模式(Observer Pattern)
- 2. 中介者模式(Mediator Pattern)
- 3. 访问者模式(Visitor Pattern)
- 4. 状态模式(State Pattern)
- 5. 策略模式(Strategy Pattern)
- 6. 命令模式(Command Pattern)
- 7. 模板模式(Template Pattern)
- 8. 责任链模式(Chain of Responsibility Pattern)
- 9. 备忘录模式(Memento Pattern)
- 10. 解释器模式(Interpreter Pattern)
- 11. 迭代器模式(Iterator Pattern)
行为型模式(Behavioral Pattern)
在系统运行时,对象之间并不是孤立的,一个对象的运行会影响到其他对象。行为型模式通过划分类和对象的职责,关注系统在运行时对象之间的交互关系。
行为型模式分为类行为型模式和对象行为型模式两种:
类行为型模式:类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
对象行为型模式:对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。
1. 观察者模式(Observer Pattern)
系统中的对象之间往往存在依赖关系,一个对象的改变会导致其他对象做出相应的反应。发生改变的叫做目标,收到改变通知的对象称作观察者,一个目标可以有多个观察者,观察者之间没有联系,方便扩展,是一种一对多的关系。每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新,故观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式。
A. 观察者模式的实现
public class ObserverPatternDemo {
public static void main(String[] arg) {
Subject sub = new Subject();
BinaryObserver bo = new BinaryObserver();
OctalObserver oo = new OctalObserver();
sub.addObserver(bo);
sub.addObserver(oo);
sub.change(3);
sub.change(8);
}
}
public interface Observer {
public void update(int i);
}
public class BinaryObserver extends Observer{
public void update(int i) {
System.out.println( "Binary String: "
+ Integer.toBinaryString(i));
}
}
public class OctalObserver extends Observer{
public void update(int i) {
System.out.println( "Octal String: "
+ Integer.toOctalString(i));
}
}
public class Subject {
private List list;
public Subject() {
list = new ArrayList<Observer>();
}
public void addObserver(Observer o) {
list.add(o);
}
public void notifyObserver(int i) {
for(Observer o : list) {
o.update(i);
}
}
public void change(int i) {
notifyObserver(i);
}
}
B. 观察者模式的优缺
优:建立一套触发机制,解耦目标与观察者,符合开闭原则
缺:若观察者与目标直接按存在循环依赖,可能导致系统崩溃
C. 观察者模式适用场景
一个对象的改变将导致其他一个或多个对象也发生改变,但不知道具体有多少对象将发生改变;或者在系统中需要创建一个触发链。观察者模式可以用来实现MVC模式,观察者模式中的观察目标就是MVC模式中的模型(Model),而观察者就是MVC中的视图(View),控制器(Controller)充当两者之间的中介者(Mediator)。当模型层的数据发生改变时,视图层将自动改变其显示内容。
2. 中介者模式(Mediator Pattern)
当对象之间存在较多直接关联关系时,一个对象的变化会导致与之相关联的所有对象都得修改,复用性差,扩展性低。为了减少对象两两之间复杂的引用关系,使之成为一个松耦合的系统,我们引入中介者模式,用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
中介者模式可以使对象之间的关系数量急剧减少。中介者主要承担两种职责。从结构上来讲起到中转作用,各个对象无需显式引用其他对象,需要通信时,通过中介者即可。从行为的较多来讲起到协调作用,中介者将对象之间的关系进行封装,将同事成员之间的关系行为进行分离和封装。
每个同事类需要通过中介者对象与其他对象交互。中介者对象一般需要保持参与通信的所有对象
- Mediator是抽象中介者,定义了同事对象到中介者对象的接口
- ConceteMediator是具体中介对象,需要直到所有参与通信的同事对象,并完成对象之间的通信
- Colleague是抽象同事类
- ConcreteColleague具体同事类,有单独的行为,不了解其他同事类的行为
A. 中介者模式的实现
public class MediatorPatternDemo {
public static void main(String[] arg) {
Mediator mailBox = new MailBox();
Colleague sender = new Sender(mailBox);
Colleague postman= new Postman(mailBoz);
sender.mail();
}
}
public interface class Mediator {
public void getMessage(Colleague c);
}
public class MailBox implements Mediator {
public void getMessage(Colleague c) {
if(c instanceof Sender) {
System.out.print("send mail");
} else if (c instanceof Postman) {
System.out.print("get mail");
}
}
}
public interface Colleague {
public void mail();
}
public class Sender implements Colleague {
private Mediator med;
public Sender(Mediator m) {
this.med = m;
}
public void mail() {
med.getMessage(this);
}
}
public class Postman implements Colleague {
private Mediator med;
public Postman(Mediator m) {
this.med = m;
}
public void mail() {
med.getMessage(this);
}
}
B. 中介者模式的优缺
优:较少了对象间得交互,将对象之间解耦
缺:中介者实现了交互细节,可能会复杂难以维护
C. 中介者模式的适应环境
对象之间存在复杂得引用关系,结构混乱,难以复用。MVC中的控制器就是中介者
3. 访问者模式(Visitor Pattern)
在大部分场景中,一个元素可能会有多个方法来操作它,而被访问对象与访问方法之间的耦合不利于访问方法的扩展。访问者模式通过将访问方法封装使之与访问对象分离,在被访问对象的类中添加一个访问自己的方法来与访问者进行关联(将访问者作为参数传入,访问者调用的是当前访问对象)。访问方法可以独立于访问对象而变化。
Visitor是抽象访问者,为具体的访问行为行为提供操作
ConcreteVisitor是具体访问者,实现具体访问方法
ObjectStructure包含参与访问的所有对象,定义接口允许访问者访问元素
Element定义一个accept方法,接收一个访问者对象
ConcreteElement为具体元素,实现accept方法
A. 访问者模式的实现
public class VisitorPatternDemo {
public static void main(String[] arg) {
Computer cmp = new Computer();
ComputerPart keyBoard = new KeyBoard("keyboard");
ComputerPart mouse = new Mouse("mouse");
ComputerVisitor visitor = new ComputerVisitor();
//ComputerVisitor visitor2 = new ComputerVisitor2();
cmp.addElement(keyBpard);
cmp.addElement(mouse);
cmp.display(visitor);
//cmp.display(visitor2);
}
}
public class Computer {
private List<ComputerPart> elements;
public Computer() {
list = new ArrayList<ComputerPart>();
}
public void addElement(Element e) {
elements.add(e);
}
public void display(Visitor v) {
for(ComputerPart cp : elements) {
//由元素发起调用,针对不同的访问方法,应用于同一元素
cp.accept(v);
}
}
}
public abstract class ComputerPart {
private String name;
public ComputerPart(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void accept(Visitor v);
}
public class KeyBord extends ComputerPart {
public KeyBord(String name) {
super(name);
}
public void accept(Visitor v) {
v.visit(this);
}
}
public class Mouse extends ComputerPart {
public Mouse(String name) {
super(name);
}
public void accept(Visitor v) {
v.visit(this);
}
}
public interface Visitor {
public void visit(ComputerPart part);
}
public class ComputerVisitor {
public void visit(ComputerPart part) {
System.out.print(part.getName());
}
}
B. 访问者模式的优缺
优:符合单一职责原则,高扩展性
缺:被访问对象变更困难
C. 访问者模式的适用场景
对象很少变化而在其上的操作经常变化
4. 状态模式(State Pattern)
在一些场景中,对象的行为会根据一些属性的取值而发生变化。这些变化的属性叫做状态,对象与外部事件的交互会使状态发生变化,行为相应也会变化。状态模式的关键是引入了一个抽象类来专门表示对象的状态,对象的每一种具体状态类都继承了该类,不同的具体状态类实现了不同状态的行为。状态与行为一一对应。
环境类是拥有状态的对象,在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象,可以定义初始状态;
抽象状态类用于定义一个接口以封装与环境类的一个特定状态相关的行为;
具体状态类是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
A. 状态模式的实现
public class StatePatternDemo {
public static void main(String[] arg) {
Switch s = new Switch();
for(int i = 0; i < 5; i++) {
s.operation();
}
}
}
public class Switch {
//初始状态
private State state;
public Switch() {
state = new Off();
}
public void setState(State s) {
this.state = s;
}
public void operation() {
System.out.println("Current state is" + this.state.name);
state.action(this);
}
}
public abstract class State {
public String name;
public State(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public abstract void action(Switch s);
}
public class Off extends State {
public Off() {
super("off");
}
public void action(Switch s) {
s.setState(new On());
}
}
public class On extends State {
public On() {
super("on");
}
public void action(Switch s) {
s.setState(new Off());
}
}
B. 状态模式的优缺
优:封装了转换规则,方便增加新状态;多个环境对象可共享一个状态对象
缺:增加类的数量,增加状态时还需修改状态转换的源码
C. 状态模式的适用
代码中包含大量与对象状态有关的条件语句;或者对象的行为依赖于状态比如代办事项,已完成,未完成等。
5. 策略模式(Strategy Pattern)
在系统设计中,实现某一功能的方式可能有多种,其中每一种方式称为一个策略。策略模式通过将每一种算法封装为独立的策略类,可以灵活的选择并添加新的策略。一般会用一个抽象的策略类来做算法的定义,而具体每种算法则对应于一个具体策略类,使算法独立于使用它的客户而变化。
A. 策略模式的实现
public class StrategyPatternDemo {
public static void main(String[] arg) {
Context c = new Context();
Strategy add = new AddStrategy();
c.setStrategy(add);
System.out.print("2+1=%d", c.execute(2, 1));
Strategy sub = new SubStrategy();
c.setStrategy(sub);
System.out.print("2-1=%d", c.execute(2, 1));
}
}
public class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy ;
}
public int execute(int x, int y) {
return strategy.operation(x, y);
}
}
public interface Strategy {
public int operation(int x, int y);
}
public class AddStrategy implements Strategy {
public int operation(int x, int y) {
return x + y;
}
}
public class SubStrategy implements Strategy {
public int operation(int x, int y) {
return x - y;
}
}
B. 策略模式的优缺
优:符合开闭原则,灵活更换或添加算法,避免多重条件转移
缺:产生多个策略类;调用端需要了解所有类略类
C. 策略模式的适用环境
系统中出现复杂多重判断;一系列算法行为需要相互替换;系统中有很多类,区别仅在于行为差异。
6. 命令模式(Command Pattern)
在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但是有时需要对行为进行记录或者撤销,紧耦合的方式就非常不便。命令模式则通过将行为抽象为对象,实现行为的请求者与接受者之间解耦,请求者与接收者之间没有直接引用关系。命令模式的本质是对命令进行封装,将命令的请求者与接收者分割开,请求放不必知道接收方的接口及命令的执行过程。命令模式的关键在于引入了抽象命令接口,命令请求者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。命令模式也称为动作(Action)模式或事务(Transaction)模式。
Invoker是调用者,命令的发送端
Receiver是接收者,命令的具体实施者
Command是命令类,对所有命令进行抽象
ConcreteCommand是具体命令,将命令的接收者与命令绑定,执行接受者的相应操作
A.命令模式的实现
public interface Command {
public void execute();
public void undo();
}
//定义一个灯类,以及对灯的操作
public class LightReceiver {
public void on() {
System.out.print("light on");
}
public void off() {
System.out.print("light off");
}
}
//定义一个开灯的命令
public class LightOnCommand implements Command {
private LightReceiver light;
public LightOnCommand(LightReceiver light) {
this.light = light;
}
public void execute() {
light.on();
}
public void undo() {
light.off();
}
}
//定义一个关灯的命令
public class LightOffCommand implements Command {
private LightReceiver light;
public LightOffCommand(LightReceiver light) {
this.light = light;
}
public void execute() {
light.off();
}
public void undo() {
light.on();
}
}
//空对象模式(Null Object Pattern)
//定义一个空命令,便于初始化,提供默认行为,省掉空操作判断
public class NullCommand implements Command {
public void execute() {}
public void undo() {}
}
public class RemoteController {
//对命令进行分组
Command[] onCommands;
Command[] offCommands;
Command undoCommand;
public RemoteController(int n) {
onCommands = new Command[n];
offCommands = new Command[n];
for(int i = 0; i < n; i++) {
onCommands[i] = new NullCommand();
offCommands[i] = new NullCommand();
}
}
public void setCommand(int num, Command onCommand, Command offCommand) {
onCommands[num] = onCommand;
offCommands[num] = offCommand;
}
public void onButton(int i) {
onCommand[i].execute();
undoCommand = onCommand[i];
}
public void offButton(int i) {
offCommand[i].execute();
undoCommand = offCommand[i];
}
public void undo() {
undoCommand.undo();
}
}
public class CommandPatternDemo {
public static void main(String[] arg) {
//定义一个遥控器和一个灯分别作为命令的发起与接受端
RemoteController controller = new RemoteController(3);
LightReceiver light = new LightReceiver();
//定义两个命令
Command lightOn = new LightOnCommand(light);
Command lightOff = new LightOffCommand(light);
//添加命令到控制器
controller.setCommand(0, lightOn, lightOff);
controller.onButton(0);
controller.offButton(0);
controller.undo();
}
}
B. 命令模式的优缺
优:降低耦合度,易添加新的命令,易实现行为的撤销操作
缺:产生过多命令类
C. 命令模式的适用场景
系统需要命令的发送与接收端解耦,不得直接交互
系统需要在不同的时间指定请求、将请求排队和执行请求。
系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
系统需要将一组操作组合在一起,即支持宏命令
7. 模板模式(Template Pattern)
在系统功能实现时可能会有很多方法算法步骤大同小异,存在通用方法,为避免重复编写,可以对方法的的公共部分进行抽象,将算法的实现延迟到子类中。通过定义方法的模板,可以在不改变算法结构的情况下按需重写方法。一般模板方法都加上 final 关键词,保证它就不会被重写,以防止恶意操作。
AbstractClass抽象类,类中实现了模板方法,定义了算法的执行框架
ConcreteClass实现了抽象类中的方法
A. 模板模式的实现
public class TemplatePatternDemo {
public static void main(String[] arg) {
Game game = new Football();
game.play();
game = new Jump();
game.play();
}
}
public abstract class Game {
public abstract void initialize();
public abstract void start();
public abstract void end();
public final void play() {
initialize();
start();
end();
}
}
public class Jump extends Game {
public abstract void initialize() {
System.out.println("initialize ...");
}
public abstract void start() {
System.out.println("start jump");
}
public abstract void end() {
System.out.println("end jump");
}
}
public class Football extends Game {
public abstract void initialize() {
System.out.println("initialize ...");
}
public abstract void start() {
System.out.println("start football");
}
public abstract void end() {
System.out.println("end football");
}
}
B. 模板模式的优缺
优:封装不变部分,扩展可变部分,行为由父类控制,实现由子类确定,易维护
缺:不同的实现都要重新定义类,可能导致类数量增加
C. 模板模式的使用场景
多个方法有公共方法且整体逻辑相同。
8. 责任链模式(Chain of Responsibility Pattern)
为避免请求的发送方与接收方耦合,可以尝试让多个对象都接收请求,把这些对象连成链,请求沿该链传递,直到有对象成功接收为止。责任链模式就是为请求创建了一个接收者对象的链来实现发送者与接收者的解耦。每个接收者包含另一个接收者的引用,如果当前对象不能处理请求则把请求传递到下一个接收者。
A. 责任链模式的实现
public class PurchaseRequest {
private float price;
public PurchaseRequest(float price) {
this.price = price;
}
public float getPrice() {
return this.price;
}
}
public abstract class Approver {
private Approver next;
private String name;
public Approver(String name) {
this.name = name;
}
public void setNext(Approver app) {
this.next = app;
}
public abstract void process(PurchaseRequest r);
}
public class DepartmentApprover extends Approver {
public DepartmentApprover(String name) {
super(name);
}
public void process(PurchaseRequest r) {
if(r.getPrice() <= 1000) {
System.out.print(r.getPrice() +"-->"+ this.name);
} else {
next.process(r);
}
}
}
public class CollegeApprover extends Approver {
public CollegeApprover(String name) {
super(name);
}
public void process(PurchaseRequest r) {
if(r.getPrice() > 1000 && r.getPrice() <= 2000) {
System.out.print(r.getPrice() +"-->"+ this.name);
} else {
next.process(r);
}
}
}
public class UniversityApprover extends Approver {
public UniversityApprover(String name) {
super(name);
}
public void process(PurchaseRequest r) {
if(r.getPrice() > 2000) {
System.out.print(r.getPrice() +"-->"+ this.name);
} else {
next.process(r);
}
}
}
public class ResponsibilityChainDemo {
public static void main(string[] arg) {
PurchaseRequest r = new PurchaseRequest(1500);
DepartmentApprover d = new DepartmentApprover("主任");
CollegeApprover c = new CollegeApprover("院长");
UniversityApprover u = new UniversityApprover("校长");
//设置为环形链,可以从任意位置开始判断
d.setNext(c);
c.setNext(u);
u.setNext(d);
d.process(r);
}
}
B. 责任链模式的优缺
优:降低耦合,方便增加新的请求处理类
缺:请求不一定被接收,不易观察运行时的特征,调试不方便
C. 责任链模式的适用场景
多个条件一次依赖;多个对象可以处理同一个请求;或者不明确接收者时,向多个对象提交一个请求;JS 中的事件冒泡
9. 备忘录模式(Memento Pattern)
在一些情况下我们需要保存对象的某个状态,允许用户错误操作后恢复之前的状态。备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便可以在以后将对象恢复到原先保存的状态。为了符合迪米特原则,还要增加一个备忘录管理类,客户端不直接与备忘录类耦合,而与备忘录管理类耦合。为了节约内存,可使用原型模式+备忘录模式。
Memento用于封装状态
Originator用于操作memento,决定存档还是读档
CareTaker用于保存记录的若干个memento
CareTaker相当于是个记事本,memento是其中的一页,originator是记录和查找的人,一次只处理一页,不让客户直接操作memento,避免强耦合。
A.备忘录模式的实现
public class MementoPatternDemo {
public static void main(String[] arg) {
//定义一个备忘录笔记本
CareTaker book = new CareTaker();
//定义一个记录笔
Originator org = new Originator();
//每一页备忘录由originator来处理
org.setState("State I");
org.setState("State II");
//创建一页备忘录,将状态II记录在案
Memento item = org.saveStateToMemento();
//提交到笔记本中
book.add(item);
org.setState("State III");
book.add(org.saveStateToMemento());
//查找状态II
item = book.get(0);
//恢复状态,将当前状态设置为状态II
org.getStateFromMemento(item);
}
}
public class Memento {
private String state;
public Memento(String s) {
state = s;
}
public String getState() {
return state;
}
}
public class CareTaker {
private List mementoList;
public CareTaker() {
mementoList = new ArrayList<Memento>();
}
public void add(Memento m) {
mementoList.add(m);
}
public Memento get(int index) {
return mementoList.get(index);
}
}
public class Originator {
private String state;
public void setState(String state){
this.state = state;
}
public Memento saveStateToMemento(){
return new Memento(state);
}
public void getStateFromMemento(Memento Memento){
state = Memento.getState();
}
}
B. 备忘录模式的优缺
优:提供了状态恢复的机制
缺:耗费资源
C. 备忘录模式的适用环境
需要恢复数据的场景中
10. 解释器模式(Interpreter Pattern)
解释器模式提供了一种解析文法或表达式的方式,通过实现一个接口来解释给定的上下文。比如sql解析等
A. 解释器模式的实现
public class InterpreterPatternDemo {
public static void main(String[] arg) {
Expression julie = new TerminalExpression("Julie");
Expression married = new TerminalExpression("Married");
Expression exp = new AndExpression(julie, married);
System.out.println("Julie is a married women? "
+ exp.interpret("Married Julie"));
}
}
public interface Expression {
public boolean interpret(String context);
}
public class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data) {
this.data = data;
}
public boolean interpret(String context) {
if(context.contains(data)) return true;
return false;
}
}
public class AndExpression implements Expression {
private Expression exp1;
private Expression exp2;
public AndExpression(Expression e1, Expression e2) {
this.exp1 = e1;
this.exp2 = e2;
}
public boolean interpret(String context) {
return exp1.interpret(context) && exp2.interpret(context);
}
}
B. 解释器模式的优缺
优:易实现简单文法,扩展性好
缺:应用场景特殊且少,复杂文法难维护,解释器模式采用递归调用
C. 解释器模式的适用场景
将要解释的句子表示为抽象语法树或复杂逻辑用简单语言来表达。Java中可以用expression4J
11. 迭代器模式(Iterator Pattern)
迭代器模式用于顺序访问集合对象的元素而无需了解集合对象的底层表示。元素间的游走操作交给迭代器而不是聚合对象。常见的接口入hasNext, next。
A. 迭代模式的实现
public class IteratorPatternDemo {
public static void main(String[] arg) {
Container record = new NameRecord();
for(Iterator it = record.getIterator(); it.hasNext();) {
System.out.println((String)it.next());
}
}
}
public interface Iterator {
public boolean hasNext();
public Object next();
}
public interface Container {
public Interator getIterator();
}
public class NameRecord implements Container {
public String[] names = {"jack", "tom", "henry"};
public Iterator getIterator() {
return new NameIterator();
}
public class NameIterator implements Iterator {
private int index = 0;
public boolean hasNext() {
if(index < names.length) return true;
return false;
}
public Object next() {
if(this.hasNext()) return names[index++];
return null;
}
}
}
B. 迭代模式的优缺
优:支持以不同的方式遍历聚合对象,方便增加新的聚合类和迭代器类
缺:迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类
C.迭代模式的适用场景
聚合对象需要多种遍历方式;或者遍历聚合对象时无需暴露内部表示
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)