目录
建造者模式
将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。用户只需指定需要建造的类型,不需要知道建造过程及细节。
建造者模式和工厂模式的区别在于,建造者模式在乎方法的调用顺序、可以创造各种不同的由不同的复杂部件组成的产品,工厂模式注重创建产品、创建出的产品都一个样子。总的来说就是,当一个对象创建需要很多步骤时,适合建造者模式,只需要一个简单的方法就可以创建的,用工厂模式。
类型:创建型
使用场景:一个有非常复杂的内部结构(许多属性)的对象,或是想把复杂对象的创建和使用分开。
优点:封装性好,建造和使用分离。扩展型好,建造类之间独立,在一定程度上解耦。
缺点:会产生多余的Builder对象,产品内部发生变化的时候,建造者都需要修改,成本较大。
例子:
public class Software {
private String name;
private String type;
private Double price;
private String describe;
private String size;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
@Override
public String toString() {
return "Software{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
", price=" + price +
", describe='" + describe + '\'' +
", size='" + size + '\'' +
'}';
}
}
public interface SoftwareBuilder {
void buildSoftwareName(String name);
void buildSoftwareType(String type);
void buildSoftwarePrice(Double price);
void buildSoftwareDescribe(String describe);
void buildSoftwareSize(String size);
Software releaseSoftware();
}
public class SoftwareActualBuilder implements SoftwareBuilder {
private Software software = new Software();
@Override
public void buildSoftwareName(String name) {
software.setName(name);
}
@Override
public void buildSoftwareType(String type) {
software.setType(type);
}
@Override
public void buildSoftwarePrice(Double price) {
software.setPrice(price);
}
@Override
public void buildSoftwareDescribe(String describe) {
software.setDescribe(describe);
}
@Override
public void buildSoftwareSize(String size) {
software.setSize(size);
}
@Override
public Software releaseSoftware() {
return software;
}
}
public class Salesman {
private SoftwareBuilder softwareBuilder;
public void setSoftwareBuilder(SoftwareBuilder softwareBuilder) {
this.softwareBuilder = softwareBuilder;
}
public Software releaseSoftware(String name , String type,
Double price , String describe,
String size){
this.softwareBuilder.buildSoftwareName(name);
this.softwareBuilder.buildSoftwareType(type);
this.softwareBuilder.buildSoftwarePrice(price);
this.softwareBuilder.buildSoftwareDescribe(describe);
this.softwareBuilder.buildSoftwareSize(size);
return this.softwareBuilder.releaseSoftware();
}
}
public class Test {
public static void main(String[] args) {
SoftwareBuilder softwareBuilder = new SoftwareActualBuilder();
Salesman salesman = new Salesman();
salesman.setSoftwareBuilder(softwareBuilder);
Software software = salesman.releaseSoftware("魔兽世界",
"游戏",
75.00,
"很好玩",
"60G"
);
System.out.println(software);
}
}
Test通过Salesman调用抽象Builder,通过传入具体Builder,Salesman返回来创建对象,不需要和具体对象打交道,这样如果有好几种商品,可以通过创建不同的Builder来实现实体的调用。
当然,上面的建造者模式结构看起来很麻烦,也跟常见的建造者模式不一样,一般来说,建造者模式的builder都是直接创建,接下来优化代码:
public class Software {
private String name;
private String type;
private Double price;
private String describe;
private String size;
public Software(SoftwareBuilder softwareBuilder) {
this.name = softwareBuilder.name;
this.type = softwareBuilder.type;
this.price = softwareBuilder.price;
this.describe = softwareBuilder.describe;
this.size = softwareBuilder.size;
}
public static class SoftwareBuilder{
private String name;
private String type;
private Double price;
private String describe;
private String size;
public SoftwareBuilder buildSoftwareName(String name){
this.name = name;
return this;
}
public SoftwareBuilder buildSoftwareType(String type) {
this.type = type;
return this;
}
public SoftwareBuilder buildSoftwarePrice(Double price) {
this.price = price;
return this;
}
public SoftwareBuilder buildSoftwareDescribe(String describe) {
this.describe = describe;
return this;
}
public SoftwareBuilder buildSoftwareSize(String size) {
this.size = size;
return this;
}
public Software build(){
return new Software(this);
}
}
@Override
public String toString() {
return "Software{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
", price=" + price +
", describe='" + describe + '\'' +
", size='" + size + '\'' +
'}';
}
}
public class Test {
public static void main(String[] args) {
Software software = new Software.SoftwareBuilder()
.buildSoftwareName("魔兽世界")
.buildSoftwareType("游戏")
.buildSoftwarePrice(75.00)
.buildSoftwareDescribe("很好玩")
.buildSoftwareSize("60G")
.build();
System.out.println(software);
}
}
用到设计模式的源码:
最典型的就是StringBuilder和StringBuffer
从这也可以看出,StringBuilder和StringBuffer的区别,也只是Buffer是同步的。
再比如:SqlSessionFactoryBuilder
里面有一堆build方法,需要注意下面这个,建造者中嵌套建造者,这也是以后编码可以参考的地方。
原型模式
原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。他不需要知道任何创建的细节,且不调用构造函数。
类型:创建型
使用场景:类初始化消耗资源过多的时候。new产生一个新的对象需要非常繁琐的过程(数据准备、访问权限等)。构造函数比较复杂的时候。循环体中生产大量对象时。
优点:性能比直接new一个对象性能高。简化创建过程。
缺点:必须配备(覆盖)克隆方法。对克隆复杂对象或克隆出的对象进行复杂改造时,容易引入风险。深拷贝、浅拷贝要运用得当。
例子:
原型模式在系统中是以二进制流的形式拷贝对象的,要比直接new一个对象性能会好很多。
想要实现克隆,实现Cloneable就可以了
public class Email implements Cloneable{
private String title;
private String address;
private String content;
public Email() {
System.out.println("Email Class Constructor");
}
@Override
protected Object clone() throws CloneNotSupportedException {
System.out.println("clone Email Object");
return super.clone();
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Email{" +
"title='" + title + '\'' +
", address='" + address + '\'' +
", content='" + content + '\'' +
'}';
}
}
public class EmailUtil {
public static void sendEmail(Email email){
String outputContent = "主题:{0},邮件地址:{1},邮件内容:{2},发送成功!";
System.out.println(MessageFormat.format(outputContent, email.getTitle()
,email.getAddress() , email.getContent()));
}
public static void saveOriginRecord(Email email){
System.out.println("存储originMail记录《" + email.getContent() + "》");
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Email email = new Email();
email.setContent("初始化模板");
for (int i = 0 ; i < 5 ; i ++){
Email mailTemp = (Email) email.clone();
mailTemp.setTitle("标题" + i);
mailTemp.setAddress("address" + i + "@haozi.com");
mailTemp.setContent("这是邮件内容");
EmailUtil.sendEmail(mailTemp);
}
EmailUtil.saveOriginRecord(email);
}
}
运行结果:
类图就不贴了,很简单,这里说一下深克隆和浅克隆,这个非常重要!
浅克隆:
public class Haozi implements Cloneable {
private String name;
private Date birthday;
public Haozi(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Haozi{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}' + super.toString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Date birthday = new Date(0L);
Haozi haozi1 = new Haozi("耗子" , birthday);
Haozi haozi2 = (Haozi) haozi1.clone();
System.out.println(haozi1);
System.out.println(haozi2);
haozi1.getBirthday().setTime(6666666666666L);
System.out.println(haozi1);
System.out.println(haozi2);
}
}
这里是为了显示某些内容,所以故意写的跟平常不一样。运行结果:
可以看出,前面我们只是调整了haozi1的日期,但是haozi2的跟这变了,通过debug可以看到,haozi2克隆了haozi1,但两个的Date对象是同一个。
深克隆,需要对需要深克隆的对象单独写克隆方法:
@Override
protected Object clone() throws CloneNotSupportedException {
Haozi haozi = (Haozi) super.clone();
haozi.birthday = (Date) haozi.birthday.clone();
return haozi;
}
这样,引用的date对象就是两个了。
用到设计模式的源码:
源于源码,ArrayList、HashMap等集合都实现了Cloneable接口,重写了clone方法,这里就不贴了,具体的自己去看。
原型模式在设计中运用非常广发,在日常使用中一定要注意深克隆和浅克隆!!