设计模式之禅之行为类PK【观察者模式VS责任链模式】 悠悠 2022-06-02 12:07 216阅读 0赞 # 设计模式之禅PK之行为类 # ### 行为类设计模式 ### * 行为类模式: * 责任链模式 * 命令模式 * 迭代器模式 * 中介者模式 * 备忘录模式 * 观察者模式 * 状态模式 * 策略模式 * 模板方法模式 * 访问者模式 ### 【观察者模式】VS【责任链模式】 ### * 为什么把观察者模式和责任链模式放在一起对比呢?看起来这两个模式没有太多的相似性,真的没有吗? * 我们在观察者中提到了触发链(也叫做观察者链),一个具体的角色既可以是观察者,也可以是被观察者,这就形成了一个观察者链,这与责任链模式非常类似,他们都实现了事务的链条化处理。 * 责任链的举例: * 当你在学校里犯错的时候,老师会给校长汇报,然后校长给你的父亲打电话,然后你的魔鬼的日子来了 * 那什么事触发链呢?--观察者/被观察者 * 当你在学校犯错的时候,老师没有汇报给校长,而是自己把它给解决了---这时候老师既是观察者,也是被观察者,事件从你犯错到老师处理,这也是一个链条结构,但是链结构中传递的事件改变了。 * 以一个具体的例子来说明两者的区别: * DNS【域名---IP地址】 * 数据量很大的DNS服务器它是怎么设计的呢? 1. 规定了每个区域的DNS服务器(Local DNS)只保留了自己区域的域名解析。对于不能解析的域名,则提交上级域名解析器解析,最终是由一台位于美国洛杉矶的顶级域名服务器进行解析,返回结果。 ### 示意图比较 ### <table style="margin-top:15px; margin-right:0px; margin-bottom:15px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <thead style="margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <tr style="margin:0px; padding:0px; border-width:1px 0px 0px; border-right-style:initial; border-bottom-style:initial; border-left-style:initial; border-right-color:initial; border-bottom-color:initial; border-left-color:initial; border-top-style:solid; border-top-color:rgb(204,204,204)"> <th style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">观察者模式</th> <th style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">责任链模式</th> </tr> </thead> <tbody style="margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <tr style="margin:0px; padding:0px; border-width:1px 0px 0px; border-right-style:initial; border-bottom-style:initial; border-left-style:initial; border-right-color:initial; border-bottom-color:initial; border-left-color:initial; border-top-style:solid; border-top-color:rgb(204,204,204)"> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)"><img src="https://i.imgur.com/z9iBxTY.png" alt="" style="margin-right:0px; margin-bottom:0px; margin-left:0px; padding:0px; border-width:0px; border-style:initial; border-color:initial; max-width:100%"></td> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)"><img src="https://i.imgur.com/4McqU4q.png" alt="" style="margin-right:0px; margin-bottom:0px; margin-left:0px; padding:0px; border-width:0px; border-style:initial; border-color:initial; max-width:100%"></td> </tr> </tbody> </table> ### 类图比较 ### <table style="margin-top:15px; margin-right:0px; margin-bottom:15px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <thead style="margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <tr style="margin:0px; padding:0px; border-width:1px 0px 0px; border-right-style:initial; border-bottom-style:initial; border-left-style:initial; border-right-color:initial; border-bottom-color:initial; border-left-color:initial; border-top-style:solid; border-top-color:rgb(204,204,204)"> <th style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">观察者模式</th> <th style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">责任链模式</th> </tr> </thead> <tbody style="margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <tr style="margin:0px; padding:0px; border-width:1px 0px 0px; border-right-style:initial; border-bottom-style:initial; border-left-style:initial; border-right-color:initial; border-bottom-color:initial; border-left-color:initial; border-top-style:solid; border-top-color:rgb(204,204,204)"> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)"><img src="https://i.imgur.com/vkW6jaC.png" alt="" style="margin-right:0px; margin-bottom:0px; margin-left:0px; padding:0px; border-width:0px; border-style:initial; border-color:initial; max-width:100%"></td> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)"><img src="https://i.imgur.com/yycTnor.png" alt="" style="margin-right:0px; margin-bottom:0px; margin-left:0px; padding:0px; border-width:0px; border-style:initial; border-color:initial; max-width:100%"></td> </tr> </tbody> </table> ### 代码来实现 ### * 观察者模式 * DnsServer # # package com.peng.pk_gc2; import java.util.Observable; import java.util.Observer; import java.util.Random; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public abstract class DnsServer extends Observable implements Observer { // 处理请求,也就是接收到事件后的处理 public void update(Observable ard0, Object arg1) { Recorder recorder = (Recorder) arg1; // 如果本机能解析 if (isLocal(recorder)) { recorder.setIp(genIpAddress()); } else { // 本机不能解析,则提交到上级DNS responUpperFromServer(recorder); } // 签名 sign(recorder); } // 作为被观察者,允许添加观察者,这里的上级一般只有一个 public void setUpperServer(DnsServer ds) { // 先清空,然后再增加 super.deleteObservers(); super.addObserver(ds); } // 向父Dns请求解析,也就是通知观察者 private void responUpperFromServer(Recorder recorder) { super.setChanged(); super.notifyObservers(recorder); } // 每个DNS服务器签上自己的名字 protected abstract void sign(Recorder recorder); // 每个DNS服务器都必须定义自己的处理级别 protected abstract boolean isLocal(Recorder recorder); // 随机产生一个IP地址,工具类 private String genIpAddress() { Random rmd = new Random(); String address = rmd.nextInt(255) + "." + rmd.nextInt(255) + "." + rmd.nextInt(255) + "." + rmd.nextInt(255); return address; } } * SHDnsServer # # package com.peng.pk_gc2; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class SHDnsServer extends DnsServer { @Override protected void sign(Recorder recorder) { recorder.setOwner("山西服务器"); } // 定义山西的处理级别 @Override protected boolean isLocal(Recorder recorder) { return recorder.getDomain().endsWith("sh.cn"); } } * ChinaTopNdnServer # # package com.peng.pk_gc2; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class ChinaTopDnsServer extends DnsServer { @Override protected void sign(Recorder recorder) { recorder.setOwner("中国顶级NDS服务器"); } @Override protected boolean isLocal(Recorder recorder) { return recorder.getDomain().endsWith(".ch"); } } * TopDnsServer # # package com.peng.pk_gc2; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class TopDnsServer extends DnsServer { @Override protected void sign(Recorder recorder) { recorder.setOwner("顶级NDS服务器"); } @Override protected boolean isLocal(Recorder recorder) { return true; } } * Recorder # # package com.peng.pk_gc2; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class Recorder { // 域名 private String domain; // IP地址 private String 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 + "\nIp地址:" + this.ip + "\n解析者:" + this.owner; return str; } } * Client # # package com.peng.pk_gc2; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class Client { /** * 功能: 返回值类型: 参数列表: * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // 山西域名服务器 DnsServer sh = new SHDnsServer(); // 中国顶级服务器 DnsServer china = new ChinaTopDnsServer(); // 顶级服务器 DnsServer top = new TopDnsServer(); // 定义查询路径 china.setUpperServer(top); sh.setUpperServer(china); // 解析域名 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 = new Recorder(); recorder.setDomain(domain); sh.update(null, recorder); System.out.println("=====DNS服务器解析结果====="); System.out.println(recorder); } } } * 执行结果 # # ====解析域名==== 请输入域名: sh.ch =====DNS服务器解析结果===== 域名:sh.ch Ip地址:172.16.10.53 解析者:山西服务器 * 注: 1. 下级节点对上级节点的顶礼膜拜 2. 上级节点对下级节点的绝对信任 * 责任链模式 * DnsServer # # package com.peng.pk_zr; import java.util.Random; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public abstract class DnsServer { // 上级DNS是谁 private DnsServer upperServer; // 解析域名 public final Recorder resolve(String domain) { Recorder Recorder = null; if (isLocal(domain)) { // 本服务器解析 Recorder = echo(domain); } else { // 本服务器不能解析 Recorder = upperServer.resolve(domain); } return Recorder; } // 指向上级DNS public void setUpperServer(DnsServer upperServer) { this.upperServer = upperServer; } // 每个DNS都有一个数据处理区 protected abstract boolean isLocal(String domain); // 每个DNS服务器都必须实现的解析任务 protected Recorder echo(String domain) { Recorder recorder = new Recorder(); // 获得IP地址 recorder.setIp(genIpAddress()); recorder.setDomain(domain); return recorder; } // 随机产生一个IP地址,工具类 private String genIpAddress() { Random rmd = new Random(); String address = rmd.nextInt(255) + "." + rmd.nextInt(255) + "." + rmd.nextInt(255) + "." + rmd.nextInt(255); return address; } } * SHDnsServer # # package com.peng.pk_zr; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class SHDnsServer extends DnsServer { @Override protected Recorder echo(String domain) { Recorder recorder = super.echo(domain); recorder.setOwner("山西NDS服务器"); return recorder; } // 定义山西的处理范围 @Override protected boolean isLocal(String domain) { return domain.endsWith("sh.ch"); } } * ChinaTopDnsServer # # package com.peng.pk_zr; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class ChinaTopDnsServer extends DnsServer { @Override protected Recorder echo(String domain) { Recorder recorder = super.echo(domain); recorder.setOwner("中国顶级NDS服务器"); return recorder; } // 定义山西的处理范围 @Override protected boolean isLocal(String domain) { return domain.endsWith(".ch"); } } * TopDnsServer # # package com.peng.pk_zr; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class TopDnsServer extends DnsServer { @Override protected Recorder echo(String domain) { Recorder recorder = super.echo(domain); recorder.setOwner("全球顶级服务器"); return recorder; } // 定义山西的处理范围 @Override protected boolean isLocal(String domain) { return true; } } * Recorder # # package com.peng.pk_zr; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class Recorder { // 域名 private String domain; // IP地址 private String 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 + "\nIp地址:" + this.ip + "\n解析者:" + this.owner; return str; } } * Client # # package com.peng.pk_zr; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * @author kungfu~peng * @data 2017年12月15日 * @description */ public class Client { /** * 功能: 返回值类型: 参数列表: * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // 山西域名服务器 DnsServer sh = new SHDnsServer(); // 中国顶级服务器 DnsServer china = new ChinaTopDnsServer(); // 顶级服务器 DnsServer top = new TopDnsServer(); // 定义查询路径 china.setUpperServer(top); sh.setUpperServer(china); // 解析域名 System.out.println("====解析域名===="); while (true) { System.out.println("\n请输入域名:"); String domain = (new BufferedReader( new InputStreamReader(System.in))).readLine(); if (domain.equalsIgnoreCase("n")) { return; } Recorder recoder = sh.resolve(domain); System.out.println("=====DNS服务器解析结果====="); System.out.println(recoder); } } } * 执行结果 # # 请输入域名: www.sh =====DNS服务器解析结果===== 域名:www.sh Ip地址:111.244.65.69 解析者:全球顶级服务器 请输入域名: sh.ch =====DNS服务器解析结果===== 域名:sh.ch Ip地址:198.80.218.93 解析者:山西NDS服务器 ### 最佳实践 ### <table style="margin-top:15px; margin-right:0px; margin-bottom:15px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <thead style="margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <tr style="margin:0px; padding:0px; border-width:1px 0px 0px; border-right-style:initial; border-bottom-style:initial; border-left-style:initial; border-right-color:initial; border-bottom-color:initial; border-left-color:initial; border-top-style:solid; border-top-color:rgb(204,204,204)"> <th style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">比较项</th> <th style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">责任链模式</th> <th style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">观察者模式【触发链】</th> </tr> </thead> <tbody style="margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <tr style="margin:0px; padding:0px; border-width:1px 0px 0px; border-right-style:initial; border-bottom-style:initial; border-left-style:initial; border-right-color:initial; border-bottom-color:initial; border-left-color:initial; border-top-style:solid; border-top-color:rgb(204,204,204)"> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">链中消息的对象</td> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">基本上不改变对象的结构</td> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">对象的结构是可以任意改变的</td> </tr> <tr style="margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:1px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; border-top-style:solid; border-top-color:rgb(204,204,204); background-color:rgb(248,248,248)"> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">上下节点的关系</td> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">上下节点没有关系,都是接收同样的对象,所传递的对象都是从链首传过来的</td> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">上下级的关系和亲密,上级对下级绝对相信,下级对上级顶礼膜拜,链中相连的节点是一个牢固的独立团体</td> </tr> <tr style="margin:0px; padding:0px; border-width:1px 0px 0px; border-right-style:initial; border-bottom-style:initial; border-left-style:initial; border-right-color:initial; border-bottom-color:initial; border-left-color:initial; border-top-style:solid; border-top-color:rgb(204,204,204)"> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">消息的分销渠道</td> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">方向单一、固定--链首到链尾</td> <td style="margin:0px; padding:6px 13px; border-color:rgb(204,204,204)">方向不固定,可以不同方向、跳跃都可以,取决于逻辑</td> </tr> </tbody> </table> ### 声明 ### * 摘自秦小波《设计模式之禅》第2版; * 仅供学习,严禁商业用途; * 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正;
相关 行为类模式:观察者模式VS责任链模式。 为什么要把观察者模式和责任链模式放在一起对比呢?看起来这两个模式没有太多的相似性,真没有吗?回答是有。我们在观察者模式中也提到了触发链(也叫做观察者)的问题,一个具体的角色既可 谁践踏了优雅/ 2024年02月19日 00:19/ 0 赞/ 59 阅读
相关 设计模式之禅之结构类PK【装饰模式VS适配器模式】 设计模式之禅PK之结构类 结构类设计模式 结构类模式: 适配器模式 桥梁模式 组合模式 装饰 不念不忘少年蓝@/ 2022年06月02日 12:26/ 0 赞/ 181 阅读
相关 设计模式之禅之结构类PK【代理模式VS装饰模式】 设计模式之禅PK之结构类 结构类设计模式 结构类模式: 适配器模式 桥梁模式 组合模式 装饰 Bertha 。/ 2022年06月02日 12:25/ 0 赞/ 197 阅读
相关 设计模式之禅之行为类PK【观察者模式VS责任链模式】 设计模式之禅PK之行为类 行为类设计模式 行为类模式: 责任链模式 命令模式 迭代器模式 中 悠悠/ 2022年06月02日 12:07/ 0 赞/ 217 阅读
相关 设计模式之禅之行为类PK【策略模式VS状态模式】 设计模式之禅PK之行为类 行为类设计模式 行为类模式: 责任链模式 命令模式 迭代器模式 中 爱被打了一巴掌/ 2022年06月02日 12:07/ 0 赞/ 202 阅读
相关 设计模式之禅之行为类PK【命令模式VS策略模式】 设计模式之禅PK之行为类 行为类设计模式 行为类模式: 责任链模式 命令模式 迭代器模式 中 红太狼/ 2022年06月02日 12:07/ 0 赞/ 171 阅读
相关 设计模式之禅之创建类PK【抽象工厂模式VS建造者模式】 设计模式之禅PK之创建类 创建类设计模式 创建类模式: 工厂方法模式 建造者模式 抽象工厂模式 矫情吗;*/ 2022年06月02日 12:07/ 0 赞/ 192 阅读
相关 设计模式之禅之创建类PK【工厂模式VS建造者模式】 设计模式之禅PK之创建类 创建类设计模式 创建类模式: 工厂方法模式 建造者模式 抽象工厂模式 ﹏ヽ暗。殇╰゛Y/ 2022年06月02日 12:07/ 0 赞/ 243 阅读
相关 设计模式之禅【观察者模式】 真刀实枪之观察者模式 韩非子身边的卧底到底是谁派来的 “知己知彼,百战不殆;不知彼知己,一胜一负;不知己不知彼,每战必殆” 那 心已赠人/ 2022年06月02日 10:51/ 0 赞/ 179 阅读
相关 设计模式之禅【责任链模式】 真刀实枪之责任链模式 “三从四德”--古代妇女的枷锁 三从:未嫁从父、既嫁从夫、夫死从子 也就是说, 港控/mmm°/ 2022年06月02日 10:50/ 0 赞/ 188 阅读
还没有评论,来说两句吧...