设计模式之禅跨战区PK
前言
- 创建类模式描述如何创建对象
- 行为类模式关注如何管理对象的行为
- 结构类模式则侧重于如何建立一个软件结构
- 实际的应用还是有重叠的,会出现一种模式适用,另一种模式也适用的情况
【策略模式】VS【桥梁模式】
- 这对冤家终于碰头了,策略模式与桥梁模式是如此的相似,简直就是孪生兄弟,要把他们分开可不太容易
- 先看看他们的类图
策略模式 | 桥梁模式 |
---|---|
- 两者之间确实很相似,如果把策略模式的环境角色更换为一个抽象类加一个实现类,或者把桥梁模式的抽象角色未实现,只有修正抽象话角色,想想看这两个类图有什么地方不一样?完全一样!正是由于类似场景的存在才导致了两者在实际应用中经常混淆的情况发生
从实例出发
- 大家都知道邮件有两种格式:
- 文本邮件(Text Mail)
- 超文本邮件(HTML Mail)
- 在文本文件中只有简单的文字信息,而在超文本邮件中可以有复杂文字(带有颜色,字体等属性)、图片、视频等
策略模式实现邮件的发送
- 使用策略模式发送邮件,认为这是两种不同的封装格式,即对于策略模式来说有两种不同的策略
- 类图设计
代码实现
-
MailTemplate
package com.peng.kzq1; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public abstract class MailTemplate { // 邮件发件人 private String from; // 邮件收件人 private String to; // 邮件标题 private String subject; // 邮件内容 private String context; // 通过构造函数传递邮件信息 public MailTemplate(String from, String to, String subject, String context) { super(); this.from = from; this.to = to; this.subject = subject; this.context = context; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getContext() { return context; } public void setContext(String context) { this.context = context; } }
-
TextMail
package com.peng.kzq1; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public class TextMail extends MailTemplate { public TextMail(String from, String to, String subject, String context) { super(from, to, subject, context); } public String getContext() { // 文本类型设置的格式为:text/plain String context = "\nContent-Type:text/plain;charset=GB2312\n" + super.getContext(); // 同时对邮件进行base64编码处理,这里用一句话代替 context = context + "\n邮件格式为:文本格式"; return context; } }
-
HtmlMail
package com.peng.kzq1; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public class HtmlMail extends MailTemplate { public HtmlMail(String from, String to, String subject, String context) { super(from, to, subject, context); } public String getContext() { // 文本类型设置的格式为:text/plain String context = "\nContent-Type:multipart/mixed;charset=GB2312\n" + super.getContext(); // 同时对邮件进行base64编码处理,这里用一句话代替 context = context + "\n邮件格式为:超文本格式"; return context; } }
-
MailServer
package com.peng.kzq1; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public class MailServer { // 发送的是哪封邮件 private MailTemplate m; public MailServer(MailTemplate m) { super(); this.m = m; } // 发送邮件 public void sendMail() { System.out.println("=====正在发送的邮件信息====="); // 发件人 System.out.println(m.getFrom()); // 收件人 System.out.println(m.getTo()); // 标题 System.out.println("邮件标题:" + m.getSubject()); // 邮件内容 System.out.println("邮件内容:" + m.getContext()); } }
-
Client
package com.peng.kzq1; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public class Client { public static void main(String[] args) { // 创建一封TEXT格式的邮件 MailTemplate m = new HtmlMail("a@a.com", "b@b.com", "外星人攻击地球了!", "结局:外星人被地球人打回老家了"); MailServer ms = new MailServer(m); ms.sendMail(); } }
-
执行结果
=====正在发送的邮件信息===== a@a.com b@b.com 邮件标题:外星人攻击地球了! 邮件内容: Content-Type:multipart/mixed;charset=GB2312 结局:外星人被地球人打回老家了 邮件格式为:超文本格式
桥梁模式实现邮件的发送
- 桥梁模式关注的是抽象和实现的分离,它是结构型模式,结构型模式研究的是如何建立一个软件结构
- 类图设计
代码实现
-
MailTemplate
package com.peng.kzq2; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public abstract class MailTemplate { // 邮件发件人 private String from; // 邮件收件人 private String to; // 邮件标题 private String subject; // 邮件内容 private String context; // 允许增加邮件发送标志 public void add(String sendInfo) { context = sendInfo + context; } // 通过构造函数传递邮件信息 public MailTemplate(String from, String to, String subject, String context) { super(); this.from = from; this.to = to; this.subject = subject; this.context = context; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getContext() { return context; } public void setContext(String context) { this.context = context; } }
-
HtmlMail
package com.peng.kzq2; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public class HtmlMail extends MailTemplate { public HtmlMail(String from, String to, String subject, String context) { super(from, to, subject, context); } public String getContext() { // 文本类型设置的格式为:text/plain String context = "\nContent-Type:multipart/mixed;charset=GB2312\n" + super.getContext(); // 同时对邮件进行base64编码处理,这里用一句话代替 context = context + "\n邮件格式为:超文本格式"; return context; } }
-
TextMail
package com.peng.kzq2; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public class TextMail extends MailTemplate { public TextMail(String from, String to, String subject, String context) { super(from, to, subject, context); } public String getContext() { // 文本类型设置的格式为:text/plain String context = "\nContent-Type:text/plain;charset=GB2312\n" + super.getContext(); // 同时对邮件进行base64编码处理,这里用一句话代替 context = context + "\n邮件格式为:文本格式"; return context; } }
-
MailServer
package com.peng.kzq2; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public abstract class MailServer { // 发送的是哪封邮件 protected MailTemplate m; public MailServer(MailTemplate m) { super(); this.m = m; } // 发送邮件 public void sendMail() { System.out.println("=====正在发送的邮件信息====="); // 发件人 System.out.println(m.getFrom()); // 收件人 System.out.println(m.getTo()); // 标题 System.out.println("邮件标题:" + m.getSubject()); // 邮件内容 System.out.println("邮件内容:" + m.getContext()); } }
-
Postfix
package com.peng.kzq2; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public class Postfix extends MailServer { public Postfix(MailTemplate m) { super(m); } // 修正邮件发送程序 public void sendMail() { String context = "Received:from xxx(ooxx) by aaa.aaaa.aaa.com(Postfix) with ESMT id asd12345\n"; super.m.add(context); super.sendMail(); } }
-
SendEmail
package com.peng.kzq2; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public class SendEmail extends MailServer { public SendEmail(MailTemplate m) { super(m); } // 修正邮件发送程序 public void sendMail() { String context = "Received:from xxx(ooxx) by aaa.aaaa.aaa.com(SendEmail) with ESMT id 6666666 2017.5.28\n"; super.m.add(context); super.sendMail(); } }
-
Client
com.peng.kzq2; /** * @author kungfu~peng * @data 2017年12月27日 * @description */ public class Client { public static void main(String[] args) { // 创建一封TEXT格式的邮件 MailTemplate m = new HtmlMail("a@a.com", "b@b.com", "外星人攻击地球了!", "结局:外星人被地球人打回老家了"); MailServer ms = new Postfix(m); ms.sendMail(); } }
-
执行结果
=====正在发送的邮件信息===== a@a.com b@b.com 邮件标题:外星人攻击地球了! 邮件内容: Content-Type:multipart/mixed;charset=GB2312 Received:from xxx(ooxx) by aaa.aaaa.aaa.com(Postfix) with ESMT id asd12345 结局:外星人被地球人打回老家了 邮件格式为:超文本格式
最佳实践
- 策略模式和桥梁模式是如此的相似,我们只能从他们的意图来分析他们
比较项 | 策略模式 | 桥梁模式 |
---|---|---|
行为模式,旨在封装一系列行为,在例子中我们认为、把邮件的必要信息(发件人、收件人、标题、内容)封装成一个对象就是一个行为,封装的个格式不同,行为也就不同 | 桥梁模式则是解决不破坏封装性的情况下如何抽取出他们的地抽象部分和部分实现部分都可以独立的变化,在例子中,我们的邮件服务器和邮件模板是不是都可以独立的变化?不管是邮件服务器还是邮件模型,只要继承了抽象类就可以继续扩展,它的主旨是建立一个不破坏封装性的可扩展性架构 | |
实现的方式 | 继承+多态 | 不破坏封装的前提下解决抽象和实现都可以独立扩展的模式--抽象化角色和实现化角色 |
- 注:这两个模式---不管黑猫还是白猫,抓住老鼠的猫就是好猫