[版权申明] 非商业目的注明出处可自由转载
出自:shusheng007
设计模式汇总篇,一定要收藏:永不磨灭的设计模式
概述
原型模式属于创建型模式,所以它是描述如何创建对象的模式。顾名思义,先搞一个原型对象出来,然后在这个原型对象的基础上修修补补再弄出一个新对象来。
我们一定要牢记设计模式是前人总结的一套可以有效解决问题的经验,不要一写代码就在考虑该使用什么设计模式,这是极其不可取的。正确的做法应该是在实现业务需求的同时,尽量遵守面向对象设计的六大设计原则即可。后期随着业务的扩展,你的代码会不断的演化和重构,在此过程中设计模式绝逼会大放异彩的。
类型
创建型(creational)
难度
2颗星
定义
使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。
你看看这定义,就是不说人话!不管它,一会通过实例意会一下,再通过使用场景知道解决什么问题就可以了
使用场景
- 当一个对象的构建代价过高时。例如某个对象里面的数据需要访问数据库才能拿到,而我们却要多次构建这样的对象。
- 当构建的多个对象,均需要处于某种原始状态时,就可以先构建一个拥有此状态的原型对象,其他对象基于原型对象来修改。
UML类图
照例上一张手撕UML类图
UML 类图也比较简单,只有两个部分
- Prototype
这个是一个接口,里面必须含有一个可以克隆自己的方法。在Java中,我们可以使用JDK自带的java.lang.Cloneable
接口来替代此接口
- ConcretePrototype
实现了Prototype
接口的原型对象,这个对象有个能力就是可以克隆自己。
实例
上回我们说到王二狗公司的大老板要看商城项目的周报表,二狗他们在开发中发现,批量导出报表时特别慢。经过调查发现是报表的主体部分特别耗时,那些头部,作者什么的都不怎么耗时。那二狗他们就在想,能不能将那些耗时的操作作为原型对象,然后在这个原型对象上添加上其他部分,对头,用原型模式可解。
假设一篇报表由报表头与报表体组成,报表体获取特别耗时,报表头不耗时,我们如何大量导出报表呢?
第一步,原型接口
原型接口必须有一个可以克隆自己的方法,反回类型为Prototype
public interface Prototype {
Prototype copy();
}
第二步,原型类
这个类就是我们的原型类,准备被其他人克隆使用的,所以其实现Prototype
接口,具备克隆的能力。根据业务需求,克隆可以是浅克隆,也可以是深克隆。
我们假设此类含有一个存放内容的List
,这些数据都是从数据库读取的相对比较耗时。假设我们要生成多篇不同报表,内容基本不变(这是要点,只有你需要的对象是可以基于原型对象的才有意义),头部要不同。
public class Report implements Prototype {
private List<String> parts;
public Report() {
this.parts = new ArrayList<>();
}
public Report(List<String> parts) {
this.parts = parts;
}
//耗时的数据加载操作
public void loadData() {
pats.clear();
parts.add("老夫聊发少年狂,左牵黄,右擎苍,锦帽貂裘,千骑卷平冈。");
parts.add("为报倾城随太守,亲射虎,看孙郎。");
parts.add("酒酣胸胆尚开张,鬓微霜,又何妨!持节云中,何日遣冯唐?");
parts.add("会挽雕弓如满月,西北望,射天狼。");
}
public List<String> getContents() {
return parts;
}
@Override
public Prototype copy() {
List<String> cloneList = new ArrayList<>(parts);
return new Report(cloneList);
}
}
第三,客户端使用
public class PrototypeClient {
public void getReport(){
//创建原型
Report reportPrototype = new Report();
//耗费资源的操作
reportPrototype.loadData();
//使用原型对象构建新的对象
Report reportWithTitle = (Report) reportPrototype.copy();
List<String> reportContent= reportWithTitle.getContents();
reportContent.add(0,"《江城子·密州出猎》");
reportContent.add(1,"----------------------------------------------------------");
for (String s : reportContent) {
System.out.println(s);
}
}
}
输出
《江城子·密州出猎》
--------------------------------------------------------------------------------
老夫聊发少年狂,左牵黄,右擎苍,锦帽貂裘,千骑卷平冈。
为报倾城随太守,亲射虎,看孙郎。
酒酣胸胆尚开张,鬓微霜,又何妨!持节云中,何日遣冯唐?
会挽雕弓如满月,西北望,射天狼。
技术要点总结
- 首先要有一个可以克隆自己的接口,例如此处的
Prototype
- 其他对象都是可以基于已经构建出来的原型对象扩展的。
优缺点
优点
有时会极大的提升程序的性能。
缺点
相对增加了系统的复杂性。
总结
设计模式值得你刻意练习!
GitHub源码地址:design-patterns
文章评论
public void loadData() {
pats.clear(); // TODO 这里单词差个字母r
parts.add("老夫聊发少年狂,左牵黄,右擎苍,锦帽貂裘,千骑卷平冈。");
parts.add("为报倾城随太守,亲射虎,看孙郎。");
parts.add("酒酣胸胆尚开张,鬓微霜,又何妨!持节云中,何日遣冯唐?");
parts.add("会挽雕弓如满月,西北望,射天狼。");
}
非常喜欢使用场景的篇幅,脱离实际场景都是在耍流氓
000