和构建模式、结构模式相比较,行为模式的内容要多一些。在设计模式中,行为模式强调的是类和对象之间的交互关系。它更多强调的是,在特定的行为场景种,使用哪一种设计模式是比较合适、比较得体的。
行为模式一般认为有11种,分别是命令模式、解释器模式、迭代模式、中介模式、备忘录模式、观察者模式、责任链模式、状态模式、策略模式、模板模式和访问者模式。
1、命令模式
命令模式的本质,是把接收命令的人、执行命令的人做了一个解耦。这样,不同的命令就成了一个个独立的个体。一个比较贴切的案例就是餐馆。餐馆里面的服务员会接收各种各样的服务要求,比如来一盘炒菜、来一个汤、来一份主食。这些点菜服务都可以看成是命令。把这些命令独立出来,并且把命令匹配给对应的执行者,这就是命令模式设计的初衷了。如果要画成类图,应该是这样的,
如果把上述图形换成java代码,应该是这样的,
import java.io.*;
class receiver
{
public void process(String s)
{
System.out.println(s);
}
}
class command
{
public void execute()
{
return;
}
}
class commandA extends command
{
private receiver r;
public commandA(receiver r)
{
this.r = r;
}
public void execute()
{
r.process("A command");
}
}
class commandB extends command
{
private receiver r;
public commandB(receiver r)
{
this.r = r;
}
public void execute()
{
r.process("B command");
}
}
class commandC extends command
{
private receiver r;
public commandC(receiver r)
{
this.r = r;
}
public void execute()
{
r.process("C command");
}
}
class waiter
{
private command cmdA;
private command cmdB;
private command cmdC;
public void setCmdA(command cmd)
{
this.cmdA = cmd;
}
public void setCmdB(command cmd)
{
this.cmdB = cmd;
}
public void setCmdC(command cmd)
{
this.cmdC = cmd;
}
public void exeCmdA()
{
this.cmdA.execute();
}
public void exeCmdB()
{
this.cmdB.execute();
}
public void exeCmdC()
{
this.cmdC.execute();
}
}
public class commandDemo
{
public static void main(String[] args)
{
waiter w = new waiter();
receiver r = new receiver();
command a = new commandA(r);
command b = new commandB(r);
command c = new commandC(r);
w.setCmdA(a);
w.setCmdB(b);
w.setCmdC(c);
w.exeCmdA();
w.exeCmdB();
w.exeCmdC();
}
}
2、解释器模式
解释器模式,比较合适拿来类比的就是编译器。每一种编程语言都有自己的文法格式,或者称之为范式。那么这些范式就是一个一个小的解释器。最简单的解释器就是int a;这种。复杂一点的解释器就是if-statement、for-statement、while-statement这种。所以,这是如果把解析的接口抽象出来,其实就是解释器模式,
如果写一个编译器,过于复杂,我们可以写一个小的解释器。比如识别ab、aabb、aaabbb、a**b这样的字符串,这样也可以说明问题,
abstract class interpret
{
abstract public boolean parse(String str);
}
class terminate extends interpret
{
public boolean parse(String str)
{
if(str.charAt(0)== 'a' && str.charAt(1) == 'b')
{
return true;
}
else
{
return false;
}
}
}
class block extends interpret
{
private interpret it;
boolean result;
int size;
public boolean parse(String str)
{
size = str.length();
if(size < 2)
{
return false;
}
if(size == 2)
{
it = new terminate();
result = it.parse(str);
return result;
}
if(str.charAt(0) != 'a' || str.charAt(size-1) != 'b')
{
return false;
}
it = new block();
result = it.parse(str.substring(1, size-1));
return result;
}
}
public class file
{
public static void main(String[] args)
{
interpret it = new block();
System.out.println(it.parse("a"));
System.out.println(it.parse("ab"));
System.out.println(it.parse("aab"));
System.out.println(it.parse("aabb"));
}
}
3、迭代器模式
迭代器模式,这个大家用的比较多。不管是c++,还是java都有对应的案例。假设有一个vector<int>的向量数组,那么就可以生成一个对应的迭代器,即vector<int>::iterator。有了这个迭代器,就可以用来增删改查,还可以灵活匹配各种算法。
目前java就有对应的iterator范例,是这样的,
import java.util.ArrayList;
import java.util.Iterator;
public class file {
public static void main(String[] args) {
ArrayList<Integer> sites = new ArrayList<Integer>();
sites.add(1);
sites.add(2);
sites.add(3);
sites.add(4);
Iterator<Integer> it = sites.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
4、中介者模式
中介者模式,顾名思义,就是之前两个对象完全没有联系,必须找一个共同的中介,才能完成信息的传递工作。现实场景中的群消息就是这种机制。一个人如果需要在群里面接收到其他人发送的消息,那就必须要绑定群组这个中介才可以。还有一个例子就是房屋买卖。房东和买房者之间一般都是不认识的,房屋交易想要达成,大多数情况下都要依赖于房产中介的协调和沟通。
如果把图形转成java代码,应该是这样的,
class mediator
{
public human[] humans = {null, null};
public void add_human(human h)
{
int i;
for(i = 0; i < 2; i++)
{
if(humans[i] == null)
{
humans[i] = h;
return;
}
}
}
public void notify(human h, String msg)
{
for(int i = 0; i < 2; i++)
{
if(humans[i] != h)
{
humans[i].receive(msg);
}
}
}
}
abstract class human
{
protected mediator m;
public human(mediator m)
{
this.m = m;
m.add_human(this);
}
abstract public void send(String msg);
abstract public void receive(String msg);
}
class A extends human
{
public A(mediator m)
{
super(m);
}
@Override
public void send(String msg)
{
System.out.println("send from " + msg +" A");
m.notify(this, msg);
}
@Override
public void receive(String msg)
{
System.out.println("receive to " + msg +" A");
}
}
class B extends human
{
public B(mediator m)
{
super(m);
}
@Override
public void send(String msg)
{
System.out.println("send "+ msg +" from B");
m.notify(this, msg);
}
@Override
public void receive(String msg)
{
System.out.println("receive "+msg +" to B");
}
}
public class mediatorDemo
{
public static void main(String []args) {
mediator m = new mediator();
human a = new A(m);
human b = new B(m);
a.send("1");
b.send("2");
a.send("3");
b.send("4");
}
}
5、备忘录模式
有过Windows操作系统经验的同学都知道,在OS出现复杂问题的时候,一般微软都会有一个选项,就是将OS恢复到之前的某个时间点。这样没有大问题的话,系统又能重新启用,不需要重装系统了。备忘录就是这么一种模式,在不同的时间点做一个备份处理,
如果把图形换算成代码,应该是这样的,
import java.io.*;
class memo
{
private int state;
public void set_state(int state)
{
this.state = state;
}
public int get_state()
{
return this.state;
}
}
class context
{
private int state;
public void set_state(int state)
{
this.state = state;
}
public int get_state()
{
return this.state;
}
public memo gen_memo()
{
memo m = new memo();
m.set_state(state);
return m;
}
public void restore_memo(memo m)
{
this.state = m.get_state();
}
}
class manager
{
private memo m;
public void set_memo(memo m)
{
this.m = m;
}
public memo get_memo()
{
return this.m;
}
}
public class memoDemo
{
public static void main(String[] args)
{
context c = new context();
c.set_state(0);
manager m = new manager();
memo m1 = c.gen_memo();
m.set_memo(m1);
c.set_state(1);
memo m2 = m.get_memo();
c.restore_memo(m2);
}
}
6、观察者模式
。目前前端开发中使用比较多的一种架构,vue.js就是用了观察者模式。有了观察者模式,编写前端的同学就可以把数据和渲染做一个解耦。数据发生改变,vue.js会自动帮助渲染。同样而言,如果有用户操作了外部控件(类似于滑动条),对应的数据也会自动发生改变。用类图来表示的话,是这样一种情形,
如果把图形转成java代码,应该是这样的,
class event
{
public observer[] obs = {null, null, null};
public void register(observer o)
{
for(int i = 0; i < 3; i++)
{
if(null == obs[i])
{
obs[i] = o;
break;
}
}
}
public void process()
{
for(int i = 0; i < 3; i++)
{
obs[i].notify_msg();
}
}
}
class observer
{
private event e;
public observer(event e)
{
this.e = e;
e.register(this);
}
public void notify_msg()
{
return;
}
}
class observer1 extends observer
{
public observer1(event e)
{
super(e);
}
@Override
public void notify_msg()
{
System.out.println("notify observer1");
}
}
class observer2 extends observer
{
public observer2(event e)
{
super(e);
}
@Override
public void notify_msg()
{
System.out.println("notify observer2");
}
}
class observer3 extends observer
{
public observer3(event e)
{
super(e);
}
@Override
public void notify_msg()
{
System.out.println("notify observer3");
}
}
public class observerDemo
{
public static void main(String []args) {
event e = new event();
observer o1 = new observer1(e);
observer o2 = new observer2(e);
observer o3 = new observer3(e);
e.process();
}
}
7、责任链模式
责任链模式是很容易和现实场景联系在一起的设计模式。比如说出差需要报销发票,这个时候不同的领导额度是不一样的,比如低于300科长可以报销,低于1000部长可以报销,低于5000可能就要总经理报销了。责任链也就是这个道理,
责任链用的也比较多,java代码是这样的,
import java.io.*;
class employee
{
protected employee next;
public employee(employee next)
{
this.next = next;
}
public void check(int e)
{
return;
}
}
class employeeA extends employee
{
public employeeA(employee next)
{
super(next);
}
@Override
public void check(int e)
{
if(e < 100)
{
System.out.println("OK for employeeA");
}
else if(null != next)
{
next.check(e);
}
else
{
System.out.println("fail for employeeA");
}
}
}
class employeeB extends employee
{
public employeeB(employee next)
{
super(next);
}
@Override
public void check(int e)
{
if(e < 1000)
{
System.out.println("OK for employeeB");
}
else if(null != next)
{
next.check(e);
}
else
{
System.out.println("fail for employeeB");
}
}
}
public class chainDemo
{
public static void main(String[] args)
{
employee e1 = new employeeB(null);
employee e2 = new employeeA(e1);
e2.check(50);
e2.check(500);
e2.check(1000);
return;
}
}
8、状态模式
状态模式其实和状态机是一个道理。不管是软件设计,还是fpga硬件设计,状态机都是使用比较多的一种方式。状态机很容易就构建一个封闭、鲁棒的系统。而设计模式,只是告诉我们如何用面向对象的语言来构建状态模式,
图形如果写成代码,应该是这样的,
class context
{
public state s;
public void set_state(state s)
{
this.s = s;
}
public void handle_context()
{
s.handle(this);
}
}
interface state
{
public void handle(context c);
}
class state1 implements state
{
@Override
public void handle(context c)
{
c.set_state(new state2());
System.out.println("state1");
}
}
class state2 implements state
{
@Override
public void handle(context c)
{
c.set_state(new state3());
System.out.println("state2");
}
}
class state3 implements state
{
@Override
public void handle(context c)
{
c.set_state(new state1());
System.out.println("state3");
}
}
public class stateDemo
{
public static void main(String []args) {
context c = new context();
c.set_state(new state1());
c.handle_context();
c.handle_context();
c.handle_context();
}
}
9、策略模式
策略模式有点类似于算法接口。不管是什么算法,对外的抽象接口都是一样的,这样对于输入数据而言,只需要在实际使用的时候,选择对应的算法,也就是对应的策略就可以了。策略模式一般和上面谈到的迭代器模式配合使用,
如果把策略转换成代码,应该是这样的,
import java.io.*;
class strategy
{
void method(int x, int y)
{
return;
}
}
class strategyA extends strategy
{
@Override
public void method(int x, int y)
{
System.out.println(x+y);
}
}
class strategyB extends strategy
{
@Override
public void method(int x, int y)
{
System.out.println(x*y);
}
}
class user
{
private int x;
private int y;
public user(int x, int y)
{
this.x = x;
this.y = y;
}
public void set_strategy(strategy s)
{
s.method(x,y);
}
}
public class strategyDemo
{
public static void main(String[] args)
{
user u = new user(3,4);
u.set_strategy(new strategyA());
u.set_strategy(new strategyB());
}
}
10、模板模式
模板模式比较有意思。有一些产品的制作流程是比较类似的,但是制作流程需要拆分成几个步骤。在每一个步骤里面,具体实施的细节又不一样。那么这个时候,就需要将每一个步骤的接口抽象出来,同时在顶层构建一个总的制作流程。这就好比,有一个统一的模板给你参考,每一个步骤也都是约定好的,但是具体每个步骤里面做什么是需要自己定义好的,
把上述图形换成java代码,应该是这样的,
class template
{
public void process()
{
processA();
processB();
processC();
}
public void processA()
{
return;
}
public void processB()
{
return;
}
public void processC()
{
return;
}
}
class templateA extends template
{
public void processA()
{
System.out.println("templateA processA");
}
public void processB()
{
System.out.println("templateA processB");
}
public void processC()
{
System.out.println("templateA processC");
}
}
class templateB extends template
{
public void processA()
{
System.out.println("templateB processA");
}
public void processB()
{
System.out.println("templateB processB");
}
public void processC()
{
System.out.println("templateB processC");
}
}
public class templateDemo
{
public static void main(String []args) {
template t1 = new templateA();
t1.process();
template t2 = new templateB();
t2.process();
}
}
11、访问者模式
在个人印象中,访问者模式用的很少。有这么一种场景,画画需要绘制各种物体,而画画本身又可以分为水墨、油画、素描等各种艺术形式。这时,为了实现绘画和具体物体之间的解耦,有必要设计一种模式来完成这一目的,我们可以先看一下这个类图,
上图中的element就是各种物体,visitor就是各种画画艺术。每种物体想通过具体的艺术形式呈现出来,这就需要visitor来帮忙了。element和visitor是通过入参来完成关联的,这是一种轻量耦合的方式。
上述图形如果要用java代码表示,可以这么写
import java.io.*;
abstract class visitor
{
abstract public void access1(element1 e1);
abstract public void access2(element2 e2);
}
class visitor1 extends visitor
{
@Override
public void access1(element1 e1)
{
System.out.println("element1 in visitor1");
}
@Override
public void access2(element2 e2)
{
System.out.println("element2 in visitor1");
}
}
class visitor2 extends visitor
{
@Override
public void access1(element1 e1)
{
System.out.println("element1 in visitor2");
}
@Override
public void access2(element2 e2)
{
System.out.println("element2 in visitor2");
}
}
abstract class element
{
abstract public void accept(visitor v);
}
class element1 extends element
{
@Override
public void accept(visitor v)
{
v.access1(this);
System.out.println("element1 processing");
}
}
class element2 extends element
{
@Override
public void accept(visitor v)
{
v.access2(this);
System.out.println("element2 processing");
}
}
public class visitDemo
{
public static void main(String[] args)
{
element e1 = new element1();
element e2 = new element2();
visitor v1 = new visitor1();
visitor v2 = new visitor2();
e1.accept(v1);
e1.accept(v2);
e2.accept(v1);
e2.accept(v2);
}
}
12、其他
虽然一下子把行为模式的11种情形都简单描述了一下,但是个人理解和实际应用往往还需要花费很多的时间的。一方面,不需要死记硬背,机械地去套用;另外一方面,软件工程也在快速发展,不能认为23种设计模式已经包含了所有的开发套路,实际应用中活学活用就好了。学习的目的不在于记忆,而在于使用和改进。