相关文章
设计模式系列java
公众号有同窗留言设计模式,才发现很久没有写设计模式了。关于建立型设计模式只差原型模式没写了,这一篇就来填补这个空缺。
设计模式
定义:用原型实例指定建立对象的种类,并经过拷贝这些原型建立新的对象。数组
在原型模式中有以下角色:微信
须要注意的是,Prototype一般是不用本身定义的,由于拷贝这个操做十分经常使用,Java中就提供了Cloneable接口来支持拷贝操做,它就是原型模式中的Prototype。固然,原型模式也未必非得去实现Cloneable接口,也有其余的实现方式。ide
原型模式的核心是clone方法,经过该方法进行拷贝,这里举一个名片拷贝的例子。
如今已经流行电子名片了,只要扫一下就能够将名片拷贝到本身的名片库中, 咱们先实现名片类。函数
public class BusinessCard implements Cloneable {
private String name;
private String company;
public BusinessCard(){
System.out.println("执行构造函数BusinessCard");
}
public void setName(String name) {
this.name = name;
}
public void setCompany(String company) {
this.company = company;
}
@Override
public BusinessCard clone() {
BusinessCard businessCard = null;
try {
businessCard = (BusinessCard) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return businessCard;
}
public void show() {
System.out.println("name:" + name);
System.out.println("company:" + company);
}
}复制代码
BusinessCard类实现了Cloneable接口,它是一个标识接口,表示这个对象是可拷贝的,只要重写clone方法就能够实现拷贝。若是实现了Cloneable接口却没有重写clone方法就会报错。须要注意的是,clone方法不是在Cloneable接口中定义的(Cloneable接口中没有定义任何方法),而是在Object中定义的。性能
public class Client {
public static void main(String[] args) {
BusinessCard businessCard = new BusinessCard();
businessCard.setName("钱三");
businessCard.setCompany("阿里");
//拷贝名片
BusinessCard cloneCard1 = businessCard.clone();
cloneCard1.setName("赵四");
cloneCard1.setCompany("百度");
BusinessCard cloneCard2 = businessCard.clone();
cloneCard2.setName("孙五");
cloneCard2.setCompany("腾讯");
businessCard.show();
cloneCard1.show();
cloneCard2.show();
}
}复制代码
除了第一个名片,其余两个名片都是经过clone方法获得的,须要注意的是,clone方法并不会执行cloneCard1和cloneCard2的构造函数,运行结果为:
执行构造函数BusinessCard
name:钱三
company:阿里
name:赵四
company:百度
name:孙五
company:腾讯this
原型模式涉及到浅拷贝和深拷贝的知识点,为了更好的理解它们,还须要举一些例子。spa
上述的例子中,BusinessCard的字段都是String类型的,若是字段是引用的类型的,会出现什么状况呢?以下所示。设计
public class DeepBusinessCard implements Cloneable {
private String name;
private Company company = new Company();
public void setName(String name) {
this.name = name;
}
public void setCompany(String name, String address) {
this.company.setName(name);
this.company.setAddress(address);
}
@Override
public DeepBusinessCard clone() {
DeepBusinessCard businessCard = null;
try {
businessCard = (DeepBusinessCard) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return businessCard;
}
public void show() {
System.out.println("name:" + name);
System.out.println("company:" + company.getName() + "-address-" + company.getAddress());
}
}复制代码
咱们定义了DeepBusinessCard 类,它的字段company是引用类型的,Company类以下所示。
public class Company {
private String name;
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}复制代码
在客户端使用DeepBusinessCard:
public class Client {
public static void main(String[] args) {
DeepBusinessCard businessCard=new DeepBusinessCard();
businessCard.setName("钱三");
businessCard.setCompany("阿里","北京望京");
DeepBusinessCard cloneCard1=businessCard.clone();
cloneCard1.setName("赵四");
cloneCard1.setCompany("百度","北京西二旗");
DeepBusinessCard cloneCard2=businessCard.clone();
cloneCard2.setName("孙五");
cloneCard2.setCompany("腾讯","北京中关村");
businessCard.show();
cloneCard1.show();
cloneCard2.show();
}
}复制代码
运行结果为:
name:钱三
company:腾讯-address-北京中关村
name:赵四
company:腾讯-address-北京中关村
name:孙五
company:腾讯-address-北京中关村
从结果能够看出company字段为最后设置的"腾讯"、"北京中关村"。这是由于Object类提供的clone方法,不会拷贝对象中的内部数组和引用对象,致使它们仍旧指向原来对象的内部元素地址,这种拷贝叫作浅拷贝。
company字段是引用类型,businessCard被拷贝后,company字段仍旧指向原来的businessCard对象的company字段的地址。这样咱们每次设置company字段,都会覆盖上一次设置的值,最终留下的就是最后一次设置的值:"腾讯"、"北京中关村"。
引用关系以下图所示。
首先须要修改Company类,以下所示。
public class Company implements Cloneable{
private String name;
private String address;
...
public Company clone(){
Company company=null;
try {
company= (Company) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return company;
}
}复制代码
为了实现Company类能被拷贝,Company类也须要实现Cloneable接口而且覆写clone方法。接着修改DeepBusinessCard的clone方法:
public class DeepBusinessCard implements Cloneable {
private String name;
private Company company = new Company();
...
@Override
public DeepBusinessCard clone() {
DeepBusinessCard businessCard = null;
try {
businessCard = (DeepBusinessCard) super.clone();
businessCard.company = this.company.clone();//1
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return businessCard;
}
...
}复制代码
在注释1处增长了对company字段的拷贝处理。最后在客户端调用,输出的结果为:
name:钱三
company:阿里-address-北京望京
name:赵四
company:百度-address-北京西二旗
name:孙五
company:腾讯-address-北京中关村
原型模式是在内存中二进制流的拷贝,要比new一个对象的性能要好,特别是须要产生大量对象时。
直接在内存中拷贝,构造函数是不会执行的,这样就减小了约束,这既是优势也是缺点,须要在实际应用中去考量。
参考资料
《大话设计模式》
《设计模式之禅》
《Android源码设计模式解析与实战》
欢迎关注个人微信公众号,第一时间得到博客更新提醒,以及更多成体系的Android相关原创技术干货。
扫一扫下方二维码或者长按识别二维码,便可关注。