学堂 学堂 学堂公众号手机端

设计模式——原型设计模式

lewis 1年前 (2024-04-21) 阅读数 18 #技术


原型设计模式定义

指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

特点

不需要知道任何创建的细节,不调用构造函数


类型:创建型使用场景

类初始化消耗较多资源
new 产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
构造函数比较复杂
循环体中生产大量对象时

原型模式优缺点

优点:
原型模式性能比直接new一个对象性能高
简化创建过程
缺点:
必须配备克隆方法
对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
深拷贝、浅拷贝要运用得当

原型——扩展:深克隆 浅克隆

实例

原型模式通过clone的方式来创建另一个对象,而不是直接调用构造方法。这里就涉及到深克隆与浅克隆的坑。

实例:Pig类需要实现Cloneable接口

public class Pig implements Cloneable {
private String name;
private Date birthday;

public Pig(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}

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;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

@Override
public String toString() {
return "Pig{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}'+super.toString();
}
}

调用

public class Test {
public static void main(String[] args) {
try {
Date birthday = new Date(0L);
Pig pig = new Pig("佩奇", birthday);
Pig pig1 = (Pig) pig.clone();
System.out.println(pig.toString());
System.out.println(pig1.toString());

pig.getBirthday().setTime(1200L);
System.out.println(pig.toString());
System.out.println(pig1.toString());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}

}
}

此时的打印信息:

Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.df.designpatterns.prototype.clone.Pig@7f31245a
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.df.designpatterns.prototype.clone.Pig@6d6f6e28
Pig{name='佩奇', birthday=Thu Jan 01 08:00:01 CST 1970}com.df.designpatterns.prototype.clone.Pig@7f31245a
Pig{name='佩奇', birthday=Thu Jan 01 08:00:01 CST 1970}com.df.designpatterns.prototype.clone.Pig@6d6f6e28

此时可以发现在只修改pig的birthday的时间的时候,pig1的时间也发生了变化。这样就出现了问题,也就是我们说的bug,不难发现要修改这个bug,需要对pig类的clone方法进行修改,如下:

    @Override
protected Object clone() throws CloneNotSupportedException {
Pig pig= (Pig) super.clone();
pig.birthday= (Date) pig.birthday.clone();
return pig;
}

即对pig中引用对象birthday也进行拷贝

修改代码之后打印如下:

Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.df.designpatterns.prototype.clone.Pig@7f31245a
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.df.designpatterns.prototype.clone.Pig@6d6f6e28
Pig{name='佩奇', birthday=Thu Jan 01 08:00:01 CST 1970}com.df.designpatterns.prototype.clone.Pig@7f31245a
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.df.designpatterns.prototype.clone.Pig@6d6f6e28
小结

原型模式使用的时候需要小心深拷贝与浅拷贝带来的bug


版权声明

本文仅代表作者观点,不代表博信信息网立场。

热门