设计模式中的行为类模式

设计模式中的行为类模式

行为类模式包括责任链模式命令模式解释器模式迭代器模式中介者模式备忘录模式观察者模式状态模式策略模式模板方法模式访问者模式

  • 责任链模式:方向是单一的。(上访,直到有一方给你直接回应)
  • 命令模式:封装命令,对动作解耦,把一个动作的执行分为命令调用者、命令接收者。(领导通过书面命令的形式下达给员工)
  • 解释器模式:定义一个解释器,使用定义的文法表示来解释语言中的句子。(定义文法:a+b+c;输入a,b,c的数据套用公式。)
  • 迭代器模式:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。(遍历容器中的元素)
  • 中介者模式:用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用。(我和房东之间的交流交给中介)
  • 备忘录模式:不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。(为对象做一个短暂的备份)
  • 观察者模式:比较灵活,其中的消息传递方式是不固定的。(提交申请,之后逐级提交,通过后原路返回,你只知道你提交给谁)
  • 状态模式:封装的是不同的状态,以达到状态切换行为随之发生改变的目的。(状态内部进行下一状态切换)
  • 策略模式:封装的是不同的算法,算法之间没有交互,以达到算法可以自由切换的目的;(多种算法随意切换)
  • 模板方法模式:就是一个框架,实现对基本方法的调度,完成固定的逻辑。(定义一个方法,将其余基本方法的逻辑包含其中)
  • 访问者模式:根据朋友的信息,执行了自己的一个方法。(普通员工和管理层信息报表)

策略模式 VS 命令模式

策略模式的意图是封装算法,它认为“算法”已经是一个完整的、不可拆分的原子业务,即其意图是让这些算法独立,并且可以相互替换,让行为的变化独立于拥有行为的客户

命令模式则是对动作的解耦,把一个动作的执行分为执行对象、执行行为,让两者相互独立而不相互影响。

策略模式和命令模式相似,特别是命令模式退化时,比如无接收者。在这种情况下,命令模式和策略模式的类图完全一样,代码实现也比较类似,但是两者还是有区别的:

★ 关注点不同

  • 策略模式关注的是算法替换的问题
  • 命令模式则关注的是解耦问题

★ 角色功能不同

  • 策略模式中的具体算法是负责一个完整算法逻辑,是不可再拆分的原子业务单元,一旦变更就是对算法整体的变更。
  • 命令模式关注命令的实现,也就是功能的实现。

★ 使用场景不同

  • 策略模式适用于算法要求变换的场景。
  • 命令模式适用于解耦两个有紧耦合关系的对象场合或者多命令多撤销的场景。

(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格式压缩这个文件”就可以了,具体由谁来执行,则由调用者负责


策略模式VS状态模式

策略模式(左图)和状态模式(右图)的通用类图非常相似,但是它们的目标是不同的,策略模式封装的是不同的算法,算法之间没有交互,以达到算法可以自由切换的目的;而状态模式封装的是不同的状态,以达到状态切换行为随之发生改变的目的。

(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();
	}
}

结果
-----小孩儿工作-----
小孩儿的工作就是玩儿!
-----成年人工作-----
成年人的工作就是自养!
-----老年人工作-----
老年人的工作就是享受!

策略模式的实现是通过分析每个人的工作方式的不同而得出三个不同的算法逻辑,状态模式则是从人的生长规律来分析,每个状态对应了不同的行为,状态改变后行为也随之改变。


责任链模式 VS 观察者模式

触发链和责任链虽然都是链结构,但是还是有区别:

★ 链中的消息对象不同:

  • 责任链模式:基本不改变消息对象的结构,从首节点传递进来Person对象,最后出来的还是Person对象。
  • 触发链模式:链中传递的对象可以自由变化,它只要求链中相邻两个节点的消息对象固定。

★ 上下节点的关系不同:

  • 责任链模式:上下节点没有关系,都是接收同样的对象,只要按照自己的逻辑处理就成。
  • 触发链模式:上下级关系很亲密,链中的任意两个相邻节点都是一个牢固的独立团体。

★ 消息的分销渠道不同:

  • 责任链模式:一个消息从链首传递进来后,就开始沿着链条向链尾运动,方向是单一的、固定的
  • 触发链模式:采用的是观察者模式,有非常大的灵活性,一个消息传递到链首后,具体怎么传递是不固定的,可以以广播方式传递,也可以以跳跃方式传递,这取决于处理消息的逻辑。

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

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥羊汤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值