建造者模式适用于创建工具须要很多步骤,但是步骤的顺序没有严格哀求的。如果一个工具有繁芜的内部构造,可以将繁芜的工具的创建和利用进行分离(如上图所示)。
建造者的角色划分:
代码案例:
// 产品类:电子邮件public class Email { private String sender; private String receiver; private String subject; private String content; public String getSender() { return sender; } public void setSender(String sender) { this.sender = sender; } public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this.receiver = receiver; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getContent() { return content; } public void setContent(String content) { this.content = content; }}// 建造者接口:电子邮件建造者public interface EmailBuilder { EmailBuilder setSender(String sender); EmailBuilder setReceiver(String receiver); EmailBuilder setSubject(String subject); EmailBuilder setContent(String content); Email build();}// 详细建造者类:电子邮件建造者实现public class EmailBuilderImpl implements EmailBuilder { private Email email; public EmailBuilderImpl() { email = new Email(); } @Override public EmailBuilder setSender(String sender) { email.setSender(sender); return this; } @Override public EmailBuilder setReceiver(String receiver) { email.setReceiver(receiver); return this; } @Override public EmailBuilder setSubject(String subject) { email.setSubject(subject); return this; } @Override public EmailBuilder setContent(String content) { email.setContent(content); return this; } @Override public Email build() { return email; }}// 客户端代码public class Client { public static void main(String[] args) { EmailBuilder emailBuilder = new EmailBuilderImpl(); Email email = emailBuilder.setSender("sender@example.com") .setReceiver("receiver@example.com") .setSubject("Hello") .setContent("This is a test email.") .build(); System.out.println("Email sent from: " + email.getSender()); System.out.println("Email received by: " + email.getReceiver()); System.out.println("Email subject: " + email.getSubject()); System.out.println("Email content: " + email.getContent()); }}
建造者在源码中实现:
在jdk中Stringbuilder,它的append()方法来构建。
在mybatis中 SqlSessionFactoryBuilder通过build()构建一个工具。
其他的源码中也有很多,比如spring中的BeanDefinitionBuilder,cacheBuilder 等等。
原型模式先容原型模式(Prototype Design Pattern)用一个已经创建的实例作为原型,通过复制该原型工具来创建一个和原型工具相同的新工具。 原型模式的核心在于拷贝原型工具。已系统中已经存在的一个原型工具为模型,通过内存二进制流进行拷贝,无需再经历工具的初始化过程。(例如我们知道的,真假孙悟空)
原型模式包含如下角色:
抽象原型类(Prototype):它是声明克隆方法的接口,是所有详细原型类的公共父类,它可以是抽象类也可以是接口.
详细原型类(ConcretePrototype):实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆工具.
客户类(Client):在客户类中,让一个原型工具克隆自身从而创建一个新的工具.由于客户类针对抽象原型类Prototype编程.因此用户可以根据须要选择详细原型类,系统具有较好的扩展性,增加或者更换详细原型类都比较方便.
// 原型接口:定义了创建工具的方法public interface Prototype { Prototype clone();}// 详细原型类:实现了原型接口的详细类public class ConcretePrototype implements Prototype { private String name; public ConcretePrototype(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Prototype clone() { try { return (Prototype) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } }}// 客户端代码public class Client { public static void main(String[] args) { ConcretePrototype prototype = new ConcretePrototype("Original"); Prototype clonedPrototype = prototype.clone(); System.out.println("Original prototype: " + prototype.getName()); System.out.println("Cloned prototype: " + ((ConcretePrototype) clonedPrototype).getName()); }}
深克隆与浅克隆
根据在复制原型工具的同时是否复制包含在原型工具中引用类型的成员变量 这个条件,原型模式的克隆机制分为两种,即浅克隆(Shallow Clone)和深克隆(Deep Clone)
1.什么是浅克隆
被复制工具的所有变量都含有与原来的工具相同的值,而所有的对其他工具的引用仍旧指向原来的工具(克隆工具与原型工具共享引用数据类型变量)。
public class ConcretePrototype implements Cloneable { public ConcretePrototype() { System.out.println("详细的原型工具创建完成!"); } @Override protected ConcretePrototype clone() throws CloneNotSupportedException { System.out.println("详细的原型工具复制成功!"); return (ConcretePrototype)super.clone(); }} @Test public void test01() throws CloneNotSupportedException { ConcretePrototype c1 = new ConcretePrototype(); ConcretePrototype c2 = c1.clone(); System.out.println("工具c1和c2是同一个工具?" + (c1 == c2)); }
2.什么是深克隆
撤除那些引用其他工具的变量,被复制工具的所有变量都含有与原来的工具相同的值。那些引用其他工具的变量将指向被复制过的新工具,而不再是原有的那些被引用的工具。换言之,深复制把要复制的工具所引用的工具都复制了一遍。
public class ConcretePrototype implements Cloneable { private Person person; public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } void show(){ System.out.println("嫌疑人姓名: " +person.getName()); } public ConcretePrototype() { System.out.println("详细的原型工具创建完成!"); } @Override protected ConcretePrototype clone() throws CloneNotSupportedException { System.out.println("详细的原型工具复制成功!"); return (ConcretePrototype)super.clone(); }}public class Person { private String name; public Person() { } public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; }}@Test public void test02() throws CloneNotSupportedException { ConcretePrototype c1 = new ConcretePrototype(); Person p1 = new Person(); c1.setPerson(p1); //复制c1 ConcretePrototype c2 = c1.clone(); //获取复制工具c2中的Person工具 Person p2 = c2.getPerson(); p2.setName("峰哥"); //判断p1与p2是否是同一工具 System.out.println("p1和p2是同一个工具?" + (p1 == p2)); c1.show(); c2.show(); }
总结原型模式的优点紧张包括以下几点:
优点:
1. 简化工具创建过程:通过复制已有工具来创建新工具,避免了繁芜的布局过程。
2. 提高效率:对付创建繁芜或耗时工具时效率较高,无需重复实行初始化等操作。
3. 方便动态扩展:可以在运行时方便地通过原型工具天生新的实例,具有一定的灵巧性。
其缺陷紧张有:
1. 须要把稳深拷贝和浅拷贝问题:如果不恰当处理可能导致数据不一致等问题。
2. 对原型工具的修正要谨慎:可能会意外影响到基于它创建的所有工具。
3. 增加了系统的繁芜性:在理解和掩护上可能会带来一定难度