文章目录

  • Prototype模式
    • 示例程序
    • 源代码
  • Builder模式
    • 示例程序
    • 源代码
  • Abstract Factory模式
    • 示例程序
    • 源代码

文章地址

前五个设计模式

Prototype模式

通过复制生成实例

有时候会有这种需求:“在不指定类名的前提下生成实例”

具体一种情况就是想要让生成实例的框架不依赖于具体的类,二是事先注册一个原型实例,然后通过复制该实例来生成新的实例

Prototype模式的思想就是通过实例来生成实例

示例程序

在本示例程序中,Product接口和Message类中完全没有出现MessageBox类和UnderlinePen类的名字,因为在代码的编写中,一旦在类中使用到了别的类的名字,就意味着该类与其他类紧密地耦合在了一起

我们在framework包中编写的类并没有牵扯到具体的类名,Product接口是连接Manager类与其他具体类之间的桥梁

源代码

framework


Product.java

package framework;public interface Product extends Cloneable{public abstract void use(String a);public abstract Product createClone();
}

Manager.java

package framework;import java.util.*;public class Manager {private HashMap showcase = new HashMap();public void register(String name, Product proto) {showcase.put(name, proto);}public Product create(String protoname) {Product product = (Product)showcase.get(protoname);return product.createClone();}
}

default


UnderlinePen.java

import framework.*;public class UnderlinePen implements Product {private char ulchar;public UnderlinePen(char ulchar) {this.ulchar = ulchar; }public void use(String s) {int length = s.getBytes().length;System.out.println("\"" + s + "\"");for(int i=0; i<length; i++) {System.out.print(ulchar);}System.out.println("");}public Product createClone() {Product p = null;try {p = (Product)clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return p;}
}

MessageBox.java

import framework.Product;public class MessageBox implements Product {private char decochar;public MessageBox(char decochar) {this.decochar = decochar; }public void use(String s) {int length = s.getBytes().length;for(int i=0; i<length+4; i++) {System.out.print(decochar);}System.out.println("");System.out.println(decochar + " " + s + " " + decochar);for (int i = 0; i < length + 4; i++) {System.out.print(decochar);}System.out.println("");}public Product createClone() {Product p = null;try {p = (Product)clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return p;}
}

main.java

import framework.Manager;
import framework.Product;public class Main {public static void main(String[] args) {Manager manager = new Manager();UnderlinePen upen = new UnderlinePen('~');MessageBox mbox = new MessageBox('*');MessageBox sbox = new MessageBox('/');manager.register("strong message", upen);manager.register("warning box", mbox);manager.register("slash box", sbox);Product p1 = manager.create("strong message");p1.use("Hello, world.");Product p2 = manager.create("warning box");p2.use("Hellp, world.");Product p3 = manager.create("slash box");p3.use("Hello, world.");}
}

下面我来稍微解释一下源代码

首先Manager类中有两个方法:registercreateClone方法,register方法负责把一个任意(实现了Product接口的)类的实例和该类的描述性字符串关联起来(使用HashMap数据结构实现,在Manager类中声明了一个showcaseHashMap对象):

showcase.put(name, proto);

createClone方法使用showcaseget方法,根据传入的参数protoname(类的描述性字符串)来得到对应类的实例,然后强转为Product类型:

Product product = (Product)showcase.get(protoname);

这时,因为Product是一个接口,而且这些类都已经实现了Product接口,因此,product可以使用usecreateClone方法,这样我们就实现了不同的对象调用同一个方法产生不同的效果,而且因为createClone方法中调用的clone方法的特性,可以确保该方法只会产生本对象的复制品,顺便提一下,要想使用clone方法,需要实现java.lang.Cloneable接口,该接口中并未定义任何方法(典型的标记接口),在本示例程序中Product接口继承了该接口,因此实现了Product接口的类的对象都可以调用clone方法来复制自身

本示例程序很好的实现了类之间的低耦合,类与类之间没有太强的依赖性

运行结果:给不同的对象传入不同的参数会产生不同的修饰效果

"Hello, world."
~~~~~~~~~~~~~
*****************
* Hellp, world. *
*****************
/
/ Hello, world. /
/

Builder模式

组装复杂的实例

示例程序

UML

源代码


Director.java

public class Director {private Builder builder;public Director(Builder builder) {this.builder = builder;}public void construct() {builder.makeTitle("Greeting");builder.makeString("从早上到下午");builder.makeItems(new String[] {"早上好。","下午好。",});builder.makeString("晚上");builder.makeItems(new String[] {"晚上好。","晚安。","再见。",});builder.close();}
}

Builder.java

public abstract class Builder {public abstract void makeTitle(String title);public abstract void makeString(String str);public abstract void makeItems(String[] items);public abstract void close();
}

TextBuilder.java

public class TextBuilder extends Builder {private StringBuffer buffer = new StringBuffer();public void makeTitle(String title) {buffer.append("============================\n");buffer.append("[" + title + "]\n");buffer.append("\n");}public void makeString(String str) {buffer.append("██" + str + "\n");buffer.append("\n");}public void makeItems(String[] items) {for (int i = 0; i < items.length; i++) {buffer.append("    " + items[i] + "\n");}buffer.append("\n");}public void close() {buffer.append("============================\n");}public String getResult() {return buffer.toString();}
}

HTMLBuilder.java

import java.io.*;public class HTMLBuilder extends Builder {private String filename;private PrintWriter writer;public void makeTitle(String title) {filename = title + ".html";try {writer = new PrintWriter(new FileWriter(filename));} catch (Exception e) {e.printStackTrace();}writer.print("<html><head><title>" + title + "</title><head><body>");writer.println("<h1>" + title + "</h1>");}public void makeString(String str) {writer.println("<p>" + str + "</p>");}public void makeItems(String[] items) {writer.println("<ul>");for (int i = 0; i < items.length; i++) {writer.print("<li>" + items[i] + "</li>");}writer.println("</ul>");}public void close() {writer.println("</body></html>");writer.close();}public String getResult() {return filename;}
}

Main.java

public class Main {public static void main(String[] args) {if(args.length != 1) {usage();System.exit(0);}if(args[0].equals("plain")) {TextBuilder textbuilder = new TextBuilder();Director director = new Director(textbuilder);director.construct();String result = textbuilder.getResult();System.out.println(result);} else if(args[0].equals("html")) {HTMLBuilder htmlbuilder = new HTMLBuilder();Director director = new Director(htmlbuilder);director.construct();String filename = htmlbuilder.getResult();System.out.println(filename + "文件编写完成。");} else {usage();System.exit(0);}}public static void usage() {System.out.println("Usage: java Main plain编写纯文本文档");System.out.println("Usage: java Main html 编写HTML文档");}
}

在本示例程序中,具体的创建者角色,是由TextBuilderHTMLBuilder两个类来创建的,在Director类中,只是调用Builder抽象类中的抽象方法,这样就能与具体的实现者:TextBuilder类和HTMLBuilder类隔离开,降低类之间的耦合

可以看到,我们在Director类中聚合了一个Builder对象,Client使用Director来创建出Builder对象,并指导该对象创建什么样的内容,具体如何创建,取决于TextBuilder类和HTMLBuilder类的实现方式

这里的组合体现在Director类中,该类组合TextBuilder类和HTMLBuilder类中的方法生成一个construct方法

Abstract Factory模式

将关联零件组装成产品

示例程序

类列表:

UML图:

源代码

factory


Factory.java

package factory;public abstract class Factory {public static Factory getFactory(String classname) {Factory factory = null;try {factory = (Factory)Class.forName(classname).newInstance();} catch (ClassNotFoundException e) {System.err.println("没有找到" + classname + "类。");} catch (Exception e) {e.printStackTrace();}return factory;}public abstract Link createLink(String caption, String url);public abstract Tray createTray(String caption);public abstract Page createPage(String title, String author);
}

Item.java

package factory;public abstract class Item {protected String caption;public Item(String caption) {this.caption = caption;}public abstract String makeHTML();
}

Link.java

package factory;public abstract class Link extends Item {protected String url;public Link(String caption, String url) {super(caption);this.url = url;}
}

Page.java

package factory;
import java.io.*;
import java.util.ArrayList;public abstract class Page {protected String title;protected String author;protected ArrayList content = new ArrayList();public Page(String title, String author) {this.title = title;this.author = author;}public void add(Item item) {content.add(item);}public void output() {try {String filename = title + ".html";Writer writer = new FileWriter(filename);writer.write(this.makeHTML());writer.close();System.out.println(filename + "编写完成。");} catch (IOException e) {e.printStackTrace();}}public abstract String makeHTML();
}

Tray.java

package factory;
import java.util.ArrayList;public abstract class Tray extends Item {protected ArrayList tray = new ArrayList();public Tray(String caption) {super(caption);}public void add(Item item) {tray.add(item);}
}

listfactory


ListFactory.java

package listfactory;
import factory.*;public class ListFactory extends Factory {public Link createLink(String caption, String url) {return new ListLink(caption, url);}public Tray createTray(String caption) {return new ListTray(caption);}public Page createPage(String title, String author) {return new ListPage(title, author);}
}

ListLink.java

package listfactory;
import factory.*;public class ListLink extends Link {public ListLink(String caption, String url) {super(caption, url);}public String makeHTML() {return "  <li><a href=\"" + url + "\">" + caption + "</a></li>\n";}
}

ListPage.java

package listfactory;
import factory.*;
import java.util.Iterator;public class ListPage extends Page {public ListPage(String title, String author) {super(title, author);}public String makeHTML() {StringBuffer buffer = new StringBuffer();buffer.append("<html><head><title>" + title + "</title></head>\n");buffer.append("<body>\n");buffer.append("<h1>" + title + "</h1>\n");buffer.append("<ul>\n");Iterator it = content.iterator();while (it.hasNext()) {Item item = (Item)it.next();buffer.append(item.makeHTML());}buffer.append("</ul>\n");buffer.append("<hr><address>" + author + "</address>");buffer.append("</body></html>\n");return buffer.toString();}
}

ListTray.java

package listfactory;
import factory.*;
import java.util.Iterator;public class ListTray extends Tray {public ListTray(String caption) {super(caption);}public String makeHTML() {StringBuffer buffer = new StringBuffer();buffer.append("<li>\n");buffer.append(caption + "\n");buffer.append("<ul>\n");Iterator it = tray.iterator();while (it.hasNext()) {Item item = (Item)it.next();buffer.append(item.makeHTML());}buffer.append("</ul>\n");buffer.append("</li>\n");return buffer.toString();}
}

tablefactory


TableFactory.java

package tablefactory;
import factory.*;public class TableFactory extends Factory {public Link createLink(String caption, String url) {return new TableLink(caption, url);}public Tray createTray(String caption) {return new TableTray(caption);}public Page createPage(String title, String author) {return new TablePage(title, author);}
}

TableList.java

package tablefactory;
import factory.*;public class TableLink extends Link {public TableLink(String caption, String url) {super(caption, url);}public String makeHTML() {return "<td><a href=\"" + url + "\">" + caption + "</a></td>\n";}
}

TablePage.java

package tablefactory;
import factory.*;
import java.util.Iterator;public class TablePage extends Page {public TablePage(String title, String author) {super(title, author);}public String makeHTML() {StringBuffer buffer = new StringBuffer();buffer.append("<html><head><title>" + title + "</title></head>\n");buffer.append("<body>\n");buffer.append("<h1>" + title + "</h1>\n");buffer.append("<table width=\"80%\" border=\"3\">\n");Iterator it = content.iterator();while (it.hasNext()) {Item item = (Item)it.next();buffer.append("<tr>" + item.makeHTML() + "</tr>");}buffer.append("</table>\n");buffer.append("<hr><address>" + author + "</address>");buffer.append("</body></html>\n");return buffer.toString();}
}

TableTray.java

package tablefactory;
import factory.*;
import java.util.Iterator;public class TableTray extends Tray {public TableTray(String caption) {super(caption);                    }public String makeHTML() {StringBuffer buffer = new StringBuffer();buffer.append("<td>");buffer.append("<table width=\"100%\" border=\"1\"><tr>");buffer.append("<td bgcolor=\"#cccccc\" align=\"center\" colspan=\""+ tray.size() + "\"><b>" + caption + "</b></td>");buffer.append("</tr>\n");buffer.append("<tr>\n");Iterator it = tray.iterator();while (it.hasNext()) {Item item = (Item)it.next();buffer.append(item.makeHTML());}buffer.append("</tr></table>");buffer.append("</td>");return buffer.toString();}
}

default


import factory.*;public class Main {public static void main(String[] args) {if (args.length != 1) {System.out.println("Usage: java Main class.name.of.ConcreteFactory");System.out.println("Example 1: java Main listfactory.ListFactory");System.out.println("Example 2: java Main tablefactory.TableFactory");System.exit(0);}//根据传入的参数来生成具体的工厂Factory factory = Factory.getFactory(args[0]);Link people = factory.createLink("人民日报", "http://www.people.com.cn/");Link gmw = factory.createLink("光明日报", "http://www.gmw.cn/");Link us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");Link jp_yahoo = factory.createLink("Yahoo!Japan", "http://www.yahoo.co.jp/");Link excite = factory.createLink("Excite", "http://www.excite.com/");Link google = factory.createLink("Google", "http://www.google.com/");Tray traynews = factory.createTray("日报");traynews.add(people);traynews.add(gmw);Tray trayyahoo = factory.createTray("Yahoo!");trayyahoo.add(us_yahoo);trayyahoo.add(jp_yahoo);Tray traysearch = factory.createTray("检索引擎");traysearch.add(trayyahoo);traysearch.add(excite);traysearch.add(google);Page page = factory.createPage("LinkPage", "杨文轩");page.add(traynews);page.add(traysearch);page.output();}
}

我发现要想真正理解这些模式,还真没那么容易,果然抽象的东西才是最难懂的东西,但同时也是层次比较高的一种概念,它完全摆脱了实际的束缚,让我们在维护和更新程序的时候变得轻松了许多

就拿上面的示例程序来说吧,我们建立了两个实际的Factory抽象类的子类,对应listfactory包和tablefactory包,而在Main函数中,我们至始至终使用的都是抽象类,这就摆脱了类的实际实现方式对程序的影响,使得整个代码拥有了一个抽象的框架,如果后期需要增加新的文档显示方式,我们可以再创建出新的抽象类的子类来实现抽象类中定义的抽象方法

Main函数根据传入的不同工厂类以不同的方式编写文档,因为实际的工厂类都继承了抽象工厂类,这其实就是一个多态,都是Factory对象,但是调用相同的方法会产生不同的效果

需要注意的是,程序在编译的时候,只会编译Main.javafactory包中的java文件,因为Main.java并没有使用另外两个包中的文件,只有必要的类才会被编译,但是如果使用的是IDE,比如eclipse,就不需要我们自己编译了,即使不必要,eclipse也会帮我们编译

只不过在使用的时候,需要使用以下形式,把指定的工厂类的名字作为参数传递给Main

java Main listfactory.ListFactory

前面之所以要加 . 是因为ListFactory在listfactory包中,而不是和Main在同一个包

结城浩《图解设计模式》笔记相关推荐

  1. 程序员的数学【结城浩】学习笔记(1-3章)0的故事,逻辑,余数

    一,0的故事     计算机为什么用2值表示?   开关链通和断开的状态     进制的转换: 将数字反复除以2,将每步所得的余数的 列逆序排列,得到二进制的表示 指数法则: 10的0次方,2的0次方 ...

  2. 知名著者结城浩:坚持做一件事而不厌倦,一旦厌倦马上更换目标

    非商业转载请注明作译者.出处,并保留本文的原始链接:http://www.ituring.com.cn/article/216181 结城浩(Hiroshi Yuki),1963年出生,居住于东京都武 ...

  3. 图解设计模式 (结城浩 著)

    第1部分 适应设计模式 第1章 Iterator(迭代器) 模式-一个一个遍历 (已看) 第2章 Adapter(适配器) 模式-加个"适配器"模式以便于复用 (已看) 第2部分 ...

  4. 阅读笔记-《图解密码技术》(日)结城浩

    第1章    环游密码世界 加密和解密 加密之前的消息称为明文(plaintest),加密之后的消息称为密文(ciphertext). 正当的接收者将密文还原为明文称为"解密",但 ...

  5. 结城浩的《图解设计模式》设计模式之Adapter模式的理解

    书中举的电源适配器的例子,还有网上各种同类的例子,无法说服我. Banner类的两个方法,代表输出交流100伏,虽然外部调用的是Print接口的要输出12伏特的方法,但是实际还是调用PrintBann ...

  6. 结城浩 java_JAVA多线程设计模式 结城浩著 PDF下载

    <JAVA多线程设计模式>中包含JAVA线程的介绍导读,12个重要的线程设计模式和全书总结以及丰富的附录内容.每一章相关线程设计模式的介绍,都举一反三使读者学习更有效率.最后附上练习问题, ...

  7. 结城浩所著《数学女孩3:哥德尔不完备定理》读书笔记

    一.哥德尔编码的奥秘 哥德尔编码建立了自然数与形式系统的映射关系,形式系统可以引用这些映射的自然数参与形式系统计算,从而在看似牢不可破的形式系统中引入了自我指涉的隐患. #mermaid-svg-T2 ...

  8. 《图解密码技术》(第三版)结城浩-知识结构整理

    由于是自己的整理的,有些地方直接略过了,上图,图链接,密码15df.  

  9. 结构型模式的设计模式笔记

    此笔记是在软件秘笈-设计模式那点事上做的笔记 一.适配器模式 1.设计思路 既有的软件结构具有稳定运行的基础,但是却无法直接利用到新的程序当中,这时就需要一个适配器,在原有内容和新的结果之间沟通,从而 ...

最新文章

  1. C语言数据段分类,13.2.1 段的分类
  2. [开发笔记]-未找到与约束ContractName Microsoft.VisualStudio.Text.ITextDocumentFactoryService...匹配的导出...
  3. 山水风景照数据集_空寂灵动 -- 李良山水画
  4. js冒泡法和数组转换成字符串
  5. 在Python中使用OpenCV(CV2)对图像进行边缘检测
  6. arm中断保护和恢复_浅谈ARM处理器的七种异常处理
  7. 没有bug队——加贝——Python 41,42
  8. 批量读写变换图片(转)
  9. [Vue.js] 基础 -- Vue简介
  10. accept 返回0_使用Vue3.0新特性造轮子 WidgetUI3.0 (Upload上传文件组件)
  11. python pyquery倒数第二个节点之前的节点_Python中PyQuery库的使用总结
  12. CCF NOI1115 找数
  13. filter在CSS中的效果
  14. 微信小程序之----加载中提示框loading
  15. 深入理解 GraphQL
  16. python自动修图软件_带走!20 个提升效率的神器工具
  17. 【100%通过率】华为OD机试真题 Java 实现【最接最大输出功率的设备 /查找充电设备组合】
  18. Intellij IDEA 配置Git并拉取项目
  19. 使用U8G2在oled屏幕上显示胡桃摇动画
  20. Android EditText密码显示隐藏和全部属性的介绍

热门文章

  1. 类型多样的食品 食物免抠摄影素材,速来收藏
  2. 将多个Excel工作薄合并成一个工作薄如操作过程
  3. 10 项目沟通管理 人人都是项目经理系列(第10/13篇)
  4. 关于Python中turtle库中简单函数的解释
  5. CRM-客户管理系统
  6. 获得六百万的宣传曝光!奥克模型公司依靠的是什么?
  7. android录制3d照片,立体看世界:3D照片/3D视频录制_手机_手机Android频道-中关村在线...
  8. 如何进行对图片的切割
  9. 性能测试,压力测试, 负载测试,稳定性测试的定义和区别
  10. mysql 廖雪峰_mysql查询(廖雪峰sql教程学习摘录)