小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
概述
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
角色
抽象原型:通常由接口或抽象类实现,给出所具有的具体原型类所需的接口。
具体原型:被复制的对象,必须实现抽象原型接口。
客户:提出创建对象的请求。
起因
小张:哥,有没有空呀?我这边又遇到难题了...
我:你小子,之前不少还跟我吹说没有你搞不定的嘛,这次又遇上什么问题了,我看看。
小张:就是这个对象,创建的时间太长了,我在循环里面创建起来太费时间了。
/**
* 具体实例对象
*/
public class MonkeyKing {
/**
* 名称
*/
private String name;
/**
* 别名
*/
private String alias;
/**
* 对手
*/
private String opponent;
public MonkeyKing(String name) {
// 模拟创建耗时
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name;
}
}
/**
* 客户端
*/
public class PrototypePatternClient {
static final String[] opponent = {"天兵", "天将"};
public static void main(String[] args) {
for(int i = 1; i <= 10; ++i){
MonkeyKing client = new MonkeyKing("齐天大圣");
client.setAlias("大圣分身" + i);
client.setOpponent(opponent[(int) (System.currentTimeMillis() % 2)]);
System.out.println(client.toString());
}
}
}
我:这样子耗时肯定长的呀,你这方法就相当于每次都需要等那块石头吸收满日月精华,然后孙悟空才横空出世。
我:你应该学学他后面的操作,拔下猴毛之后一吹,就变出很多分身出来,这样遇敌的时候才能及时迎敌。
模板
具体原型:实现Cloneable接口,重写clone方法。
/**
* 实现 Cloneable 接口
*/
public class MonkeyKing implements Cloneable{
/**
* 名称
*/
private String name;
/**
* 别名
*/
private String alias;
/**
* 对手
*/
private String opponent;
/**
* 克隆对象
*/
@Override
protected MonkeyKing clone() {
System.out.println("拔下猴毛,吹毛成兵");
MonkeyKing monkeyKing = null;
try {
monkeyKing = (MonkeyKing)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return monkeyKing;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public String getOpponent() {
return opponent;
}
public void setOpponent(String opponent) {
this.opponent = opponent;
}
public MonkeyKing(String name) {
this.name = name;
}
@Override
public String toString() {
return "分身:【" + this.alias + "】找上了【" + this.opponent + "】做对手";
}
}
客户端:获取对象。
public class PrototypePatternClient {
static final String[] opponent = {"天兵", "天将"};
public static void main(String[] args) {
MonkeyKing monkeyKing = new MonkeyKing("齐天大圣");
for(int i = 1; i <= 10; ++i){
MonkeyKing mk = monkeyKing.clone();
mk.setAlias("大圣分身" + i);
mk.setOpponent(opponent[(int) (System.currentTimeMillis() % 2)]);
System.out.println(mk.toString());
}
}
}
小结
优点
性能:原型模式是在内存二进制流的复制,要比直接new一个对象性能好,特别是在一个循环体内产生大量的对象时,原型模式可以更好的提现其特点。
减少约束:直接在内存中复制,可以绕开构造函数的约束,减少创建的限制与耗时,但在实际应用中需谨慎考虑。
适用场景
- 在类初始化需要消耗非常多的资源(包括但不限于数据,硬件资源等)时,可以使用原型模式
- 创建一个对象需要非常繁琐的数据或访问权限时,可以使用原型模式
- 一个对象需要提供给多个修改者进行访问,而且各个修改者均可能对其进行修改时,可以使用原型模式