行为类模式包括责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式。
策略模式的意图是封装算法,它认为“算法”已经是一个完整的、不可拆分的原子业务,即其意图是让这些算法独立,并且可以相互替换,让行为的变化独立于拥有行为的客户;
命令模式则是对动作的解耦,把一个动作的执行分为执行对象、执行行为,让两者相互独立而不相互影响。
策略模式和命令模式相似,特别是命令模式退化时,比如无接收者。在这种情况下,命令模式和策略模式的类图完全一样,代码实现也比较类似,但是两者还是有区别的:
★ 关注点不同
★ 角色功能不同
★ 使用场景不同
(1)策略模式
zip压缩算法和gzip压缩算法可以互相替换,一个文件或者目录可以使用zip压缩,也可以使用gzip压缩,选择哪种压缩算法是由高层模块(实际操作者)决定的。
public interface Algorithm {
public boolean compress(String source,String to);
public boolean uncompress(String source,String to);
}
import com.sfq.impl.Algorithm;
public class Zip implements Algorithm {
@Override
public boolean compress(String source, String to) {
System.out.println(source + " --> " + to + " ZIP压缩成功!");
return true;
}
@Override
public boolean uncompress(String source, String to) {
System.out.println(source + " --> " + to + " ZIP解压成功!");
return true;
}
}
import com.sfq.impl.Algorithm;
public class Gzip implements Algorithm {
@Override
public boolean compress(String source, String to) {
System.out.println(source + " --> " + to + " GZIP压缩成功!");
return true;
}
@Override
public boolean uncompress(String source, String to) {
System.out.println(source + " --> " + to + " GZIP解压成功!");
return true;
}
}
方法定义完成,接下来就是封装:
import com.sfq.impl.Algorithm;
public class Context {
private Algorithm algorithm;
public Context(Algorithm algorithm) {
this.algorithm = algorithm;
}
//执行压缩
public boolean compress(String source,String to) {
return algorithm.compress(source, to);
}
//执行解压
public boolean uncompress(String source,String to) {
return algorithm.uncompress(source, to);
}
}
import com.sfq.action.Context;
import com.sfq.action.Zip;
public class Client {
public static void main(String[] args) {
//定义环境角色
Context context;
System.out.println("----执行压缩-----");
context = new Context(new Zip());
context.compress("c:\\windows", "d:\\windows.zip");
context.uncompress("c:\\windows.zip", "d:\\windows");
}
}
结果
----执行压缩-----
c:\windows --> d:\windows.zip ZIP压缩成功!
c:\windows.zip --> d:\windows ZIP解压成功!
策略模式关心的是算法是否可以相互替换。
(2)命令模式
命令模式的主旨是封装命令,使请求者与实现者解耦。例如,到饭店点菜,客人(请求者)通过服务员(调用者)向厨师(接收者)发送了订单(行为的请求)。
通过定义具体命令完成文件的压缩、解压缩任务,注意这里对文件的每一个操作都是封装好的命令,对于给定的请求,命令不同,处理的结果当然也不同,这就是命令模式要强调的。
接收者,即实现者的定义:
public interface IReceiver {
public boolean compress(String source,String to);
public boolean uncompress(String source,String to);
}
import com.sfq.impl.IReceiver;
public class ZipReceiver implements IReceiver {
@Override
public boolean compress(String source, String to) {
System.out.println(source + " --> " + to + " ZIP压缩成功!");
return true;
}
@Override
public boolean uncompress(String source, String to) {
System.out.println(source + " --> " + to + " ZIP解压成功!");
return true;
}
}
import com.sfq.impl.IReceiver;
public class GzipReceiver implements IReceiver {
@Override
public boolean compress(String source, String to) {
System.out.println(source + " --> " + to + " GZIP压缩成功!");
return true;
}
@Override
public boolean uncompress(String source, String to) {
System.out.println(source + " --> " + to + " GZIP解压成功!");
return true;
}
}
抽象命令类及相关命令定义:
import com.sfq.action.GzipReceiver;
import com.sfq.action.ZipReceiver;
public abstract class AbstractCmd {
//对接收者的引用
protected IReceiver zip = new ZipReceiver();
protected IReceiver gzip = new GzipReceiver();
//命令的具体单元
public abstract boolean execute(String source,String to);
}
import com.sfq.impl.AbstractCmd;
public class ZipCompressCmd extends AbstractCmd {
@Override
public boolean execute(String source, String to) {
return super.zip.compress(source, to);
}
}
import com.sfq.impl.AbstractCmd;
public class ZipUnompressCmd extends AbstractCmd {
@Override
public boolean execute(String source, String to) {
return super.zip.uncompress(source, to);
}
}
import com.sfq.impl.AbstractCmd;
public class GZipCompressCmd extends AbstractCmd {
@Override
public boolean execute(String source, String to) {
return super.gzip.compress(source, to);
}
}
import com.sfq.impl.AbstractCmd;
public class GZipUncompressCmd extends AbstractCmd {
@Override
public boolean execute(String source, String to) {
return super.gzip.uncompress(source, to);
}
}
调用者,即请求者定义:
import com.sfq.impl.AbstractCmd;
public class Invoker {
private AbstractCmd cmd;
public Invoker(AbstractCmd cmd) {
this.cmd = cmd;
}
//执行命令
public boolean execute(String source,String to) {
return cmd.execute(source, to);
}
}
场景类实现:
import com.sfq.action.Invoker;
import com.sfq.action.ZipCompressCmd;
import com.sfq.impl.AbstractCmd;
public class Client {
public static void main(String[] args) {
//定义一个压缩文件命令
AbstractCmd cmd = new ZipCompressCmd();
//定义调用者
Invoker invoker = new Invoker(cmd);
System.out.println("-----执行压缩命令-----");
invoker.execute("c:\\windows", "d:\\windows.zip");
}
}
结果
-----执行压缩命令-----
c:\windows --> d:\windows.zip ZIP压缩成功!
命令模式的实现是关注了命令的封装,是请求者与执行者彻底分开,执行者不用了解命令的具体执行者,它只要封装一个命令——“给我用zip格式压缩这个文件”就可以了,具体由谁来执行,则由调用者负责。
策略模式(左图)和状态模式(右图)的通用类图非常相似,但是它们的目标是不同的,策略模式封装的是不同的算法,算法之间没有交互,以达到算法可以自由切换的目的;而状态模式封装的是不同的状态,以达到状态切换行为随之发生改变的目的。
(1)策略模式
人的一生有三个时期,孩童时期——玩耍;成人时期——养活自己;老年时期——伊享天年。这三种不同的工作方式就是三个不同的具体算法,随着时光的推移工作内容随之更替。
public abstract class WorkAlgorithm {
public abstract void work();
}
import com.sfq.impl.WorkAlgorithm;
public class ChildWork extends WorkAlgorithm {
@Override
public void work() {
System.out.println("小孩儿的工作就是玩儿!");
}
}
import com.sfq.impl.WorkAlgorithm;
public class AdultWork extends WorkAlgorithm {
@Override
public void work() {
System.out.println("成年人的工作就是自养!");
}
}
import com.sfq.impl.WorkAlgorithm;
public class OldWork extends WorkAlgorithm {
@Override
public void work() {
System.out.println("老年人的工作就是享受!");
}
}
import com.sfq.impl.WorkAlgorithm;
public class Context {
private WorkAlgorithm workMethod;
public WorkAlgorithm getWork() {
return workMethod;
}
public void setWork(WorkAlgorithm work) {
this.workMethod = work;
}
//每个算法都必须实现的功能
public void work() {
workMethod.work();
}
}
import com.sfq.action.AdultWork;
import com.sfq.action.ChildWork;
import com.sfq.action.Context;
import com.sfq.action.OldWork;
public class Client {
public static void main(String[] args) {
Context context = new Context();
System.out.println("-----小孩儿工作-----");
context.setWork(new ChildWork());
context.work();
System.out.println("-----成年人工作-----");
context.setWork(new AdultWork());
context.work();
System.out.println("-----老年人工作-----");
context.setWork(new OldWork());
context.work();
}
}
结果
-----小孩儿工作-----
小孩儿的工作就是玩儿!
-----成年人工作-----
成年人的工作就是自养!
-----老年人工作-----
老年人的工作就是享受!
实现了“工作”这个策略的三种不同算法,算法可以自由切换,到底用哪个算法由调用者(高层模块)决定。
(2)状态模式
人的状态(孩童、成人、老人)产生了不同的行为结果,这里的行为都是工作,但是它们的实现方式确实不同,也就是产生的结果不同。
import com.sfq.action.Human;
public abstract class HumanState {
protected Human human;
public void setHuman(Human human) {
this.human = human;
}
public abstract void work();
}
import com.sfq.impl.HumanState;
public class ChildState extends HumanState {
@Override
public void work() {
System.out.println("小孩儿的工作就是玩儿!");
super.human.setState(Human.ADULT_STATE);
}
}
import com.sfq.impl.HumanState;
public class AdultState extends HumanState {
@Override
public void work() {
System.out.println("成年人的工作就是自养!");
super.human.setState(Human.OLD_STATE);
}
}
import com.sfq.impl.HumanState;
public class OldState extends HumanState {
@Override
public void work() {
System.out.println("老年人的工作就是享受!");
}
}
import com.sfq.impl.HumanState;
public class Human {
//定义人类的状态
public static final HumanState CHIILD_STATE = new ChildState();
public static final HumanState ADULT_STATE = new AdultState();
public static final HumanState OLD_STATE = new OldState();
//定义一个人的状态
private HumanState state;
public void setState(HumanState state) {
this.state = state;
this.state.setHuman(this);
}
//人类的工作
public void work() {
this.state.work();
}
}
import com.sfq.action.ChildState;
import com.sfq.action.Human;
public class Client {
public static void main(String[] args) {
//定义一个普通人
Human human = new Human();
//设置初始状态
human.setState(new ChildState());
System.out.println("-----小孩儿工作-----");
human.work();
System.out.println("-----成年人工作-----");
human.work();
System.out.println("-----老年人工作-----");
human.work();
}
}
结果
-----小孩儿工作-----
小孩儿的工作就是玩儿!
-----成年人工作-----
成年人的工作就是自养!
-----老年人工作-----
老年人的工作就是享受!
策略模式的实现是通过分析每个人的工作方式的不同而得出三个不同的算法逻辑,状态模式则是从人的生长规律来分析,每个状态对应了不同的行为,状态改变后行为也随之改变。
触发链和责任链虽然都是链结构,但是还是有区别:
★ 链中的消息对象不同:
★ 上下节点的关系不同:
★ 消息的分销渠道不同:
DNS协议规定每个区域的DNS服务器(Local DNS)只保留自己区域的域名解析,对于不能解析的域名,则提交上级域名解析器解析,最终由一台位于美国洛杉矶的顶级域名服务器进行解析,返回结果。
(1)责任链模式
这里有三个服务器,根据DNS的解析方式得到下图:
类图中,Recorder是一个BO对象,它记录DNS服务器解析后的结果,包括域名、IP地址、属主(即由谁解析的)。
public class Recorder {
private String domain; //域名
private String ip; //ip地址
private String owner; //属主
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
//输出记录信息
@Override
public String toString() {
String str = "域名:" + this.domain;
str = str + "\nIP地址:" + this.ip;
str = str + "\n解析者:" + this.owner;
return str;
}
}
import java.util.Random;
import com.sfq.action.Recorder;
public abstract class DnsServer {
//上级DNS
private DnsServer upperServer;
public void setUpperServer(DnsServer upperServer) {
this.upperServer = upperServer;
}
//解析域名
public final Recorder resolve(String domain) {
Recorder recorder = null;
if (isLocal(domain)) {
recorder = echo(domain);
} else {
recorder = upperServer.resolve(domain);
}
return recorder;
}
//每个DNS都有一个数据处理区,检查域名是否在本区中
protected abstract boolean isLocal(String domain);
//每个DNS服务器都必须实现解析任务
protected Recorder echo(String domain) {
Recorder recorder = new Recorder();
//获得ip地址
recorder.setIp(getIpAddress());
recorder.setDomain(domain);
return recorder;
}
//随机产生一个ip地址
private String getIpAddress() {
Random random = new Random();
String address = random.nextInt(255) + "." + random.nextInt(255) + "." + random.nextInt(255) + "." + random.nextInt(255);
return address;
}
}
import com.sfq.impl.DnsServer;
public class SHDnsServer extends DnsServer {
@Override
protected Recorder echo(String domain) {
Recorder recorder = super.echo(domain);
recorder.setOwner("上海DNS服务器");
return recorder;
}
@Override
protected boolean isLocal(String domain) {
return domain.endsWith(".sh.cn");
}
}
import com.sfq.impl.DnsServer;
public class ChinaTopDnsServer extends DnsServer {
@Override
protected Recorder echo(String domain) {
Recorder recorder = super.echo(domain);
recorder.setOwner("中国顶级DNS服务器");
return recorder;
}
@Override
protected boolean isLocal(String domain) {
return domain.endsWith(".cn");
}
}
import com.sfq.impl.DnsServer;
public class TopDnsServer extends DnsServer {
@Override
protected Recorder echo(String domain) {
Recorder recorder = super.echo(domain);
recorder.setOwner("全球顶级DNS服务器");
return recorder;
}
@Override
protected boolean isLocal(String domain) {
return true;
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import com.sfq.action.ChinaTopDnsServer;
import com.sfq.action.Recorder;
import com.sfq.action.SHDnsServer;
import com.sfq.action.TopDnsServer;
import com.sfq.impl.DnsServer;
public class Client {
public static void main(String[] args) throws Exception {
//域名服务器
DnsServer sh = new SHDnsServer();
DnsServer china = new ChinaTopDnsServer();
DnsServer top = new TopDnsServer();
//定义路径
sh.setUpperServer(china);
china.setUpperServer(top);
System.out.println("-----域名解析-----");
while (true) {
System.out.println("请输入域名(输入n退出):");
String domain = (new BufferedReader(new InputStreamReader(System.in))).readLine();
if (domain.equalsIgnoreCase("n")) {
return;
}
Recorder recorder = sh.resolve(domain);
System.out.println("-----DNS服务器解析结果-----");
System.out.println(recorder);
}
}
}
结果
-----域名解析-----
请输入域名(输入n退出):
www.xxx.sh.cn
-----DNS服务器解析结果-----
域名:www.xxx.sh.cn
IP地址:65.209.77.188
解析者:上海DNS服务器
请输入域名(输入n退出):
www.xxx.com.cn
-----DNS服务器解析结果-----
域名:www.xxx.com.cn
IP地址:88.16.118.245
解析者:中国顶级DNS服务器
请输入域名(输入n退出):
www.xxx.com
-----DNS服务器解析结果-----
域名:www.xxx.com
IP地址:185.213.168.21
解析者:全球顶级DNS服务器
请输入域名(输入n退出):
n
(2)观察者模式
实际的DNS解析过程是逐级进行解析请求,然后结果再逐级回传,过程示意图如下:
整个场景中,我们把请求者看成是被观察者,它的行为或属性变更通知了观察者——上海DNS,上海DNS又作为被观察者出现了自己不能处理的行为,通知中国顶级DNS,依次类推,形成了一个非常标准的触发链,而且还必须是同步的触发。
public class Recorder {
private String domain; //域名
private String ip; //ip地址
private String owner; //属主
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
//输出记录信息
@Override
public String toString() {
String str = "域名:" + this.domain;
str = str + "\nIP地址:" + this.ip;
str = str + "\n解析者:" + this.owner;
return str;
}
}
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import com.sfq.action.Recorder;
public abstract class DnsServer extends Observable implements Observer {
//接收到事件后处理请求
@Override
public void update(Observable arg0, Object arg1) {
Recorder recorder = (Recorder)arg1;
//如果本机能够解析
if (isLocal(recorder)) {
recorder.setIp(getIpAddress());
} else {
responsFromUpperServer(recorder);
}
sign(recorder);
}
//作为被观察者,应该可以增加观察者
public void setUpperServer(DnsServer dnsServer) {
super.deleteObservers();
super.addObserver(dnsServer);
}
//改变状态,通知观察者。也就是向父类DNS请求解析
private void responsFromUpperServer(Recorder recorder) {
super.setChanged();
super.notifyObservers(recorder);
}
//随机产生一个IP
private String getIpAddress() {
Random random = new Random();
String address = random.nextInt(255) + "." + random.nextInt(255) + "." + random.nextInt(255) + "." + random.nextInt(255);
return address;
}
//每个DNS都有一个数据处理区,检查域名是否在本区中
protected abstract boolean isLocal(Recorder recorder);
//每个DNS服务器签上自己的名字
protected abstract void sign(Recorder recorder);
}
import com.sfq.impl.DnsServer;
public class SHDnsServer extends DnsServer {
@Override
protected boolean isLocal(Recorder recorder) {
return recorder.getDomain().endsWith(".sh.cn");
}
@Override
protected void sign(Recorder recorder) {
recorder.setOwner("上海DNS服务器");
}
}
import com.sfq.impl.DnsServer;
public class ChinaTopDnsServer extends DnsServer {
@Override
protected boolean isLocal(Recorder recorder) {
return recorder.getDomain().endsWith(".cn");
}
@Override
protected void sign(Recorder recorder) {
recorder.setOwner("中国顶级DNS服务器");
}
}
import com.sfq.impl.DnsServer;
public class TopDnsServer extends DnsServer {
@Override
protected boolean isLocal(Recorder recorder) {
return true;
}
@Override
protected void sign(Recorder recorder) {
recorder.setOwner("全球顶级DNS服务器");
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import com.sfq.action.ChinaTopDnsServer;
import com.sfq.action.Recorder;
import com.sfq.action.SHDnsServer;
import com.sfq.action.TopDnsServer;
import com.sfq.impl.DnsServer;
public class Client {
public static void main(String[] args) throws Exception{
//域名服务器
DnsServer sh = new SHDnsServer();
DnsServer china = new ChinaTopDnsServer();
DnsServer top = new TopDnsServer();
sh.setUpperServer(china);
china.setUpperServer(top);
System.out.println("\n-----域名解析-----");
while (true) {
System.out.println("请输入域名(输入n退出):");
String domain = (new BufferedReader(new InputStreamReader(System.in))).readLine();
if (domain.equalsIgnoreCase("n")) {
return;
}
Recorder recorder = new Recorder();
recorder.setDomain(domain);
sh.update(null, recorder);
System.out.println("-----DNS服务器解析结果-----");
System.out.println(recorder);
}
}
}
结果
-----域名解析-----
请输入域名(输入n退出):
www.xxx.sh.cn
-----DNS服务器解析结果-----
域名:www.xxx.sh.cn
IP地址:100.237.129.108
解析者:上海DNS服务器
请输入域名(输入n退出):
www.xxx.com.cn
-----DNS服务器解析结果-----
域名:www.xxx.com.cn
IP地址:106.89.233.55
解析者:上海DNS服务器
请输入域名(输入n退出):
www.xxx.com
-----DNS服务器解析结果-----
域名:www.xxx.com
IP地址:200.235.64.77
解析者:上海DNS服务器
请输入域名(输入n退出):
n