- 为什么使用原型模式
1、假如我有一个对象,如下:
public static void main(String[] args) {
// 创建对象
Condition condition1 = new Condition.Builder()
.setStr1("aa")
.setStr2("bb")
.setStr3("cc")
.setStr4("dd")
.setStr5("ee")
.setStr6("rr")
.setStr7("tt")
.setStr8("yy")
.setStr9("uu")
.setStr10("ii")
.build();
System.out.println("condition1:"+condition1.toString());
}
输出:
condition1:Condition{str1='aa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
2、我还想要一个对象,但是除了属性 str1 的值不一样之外,其他的值都一样,怎么办?
public static void main(String[] args) {
// 创建对象
Condition condition1 = new Condition.Builder()
.setStr1("aa")
.setStr2("bb")
.setStr3("cc")
.setStr4("dd")
.setStr5("ee")
.setStr6("rr")
.setStr7("tt")
.setStr8("yy")
.setStr9("uu")
.setStr10("ii")
.build();
System.out.println("condition1:"+condition1.toString());
Condition condition2 = new Condition.Builder()
.setStr1("aaaa")
.setStr2("bb")
.setStr3("cc")
.setStr4("dd")
.setStr5("ee")
.setStr6("rr")
.setStr7("tt")
.setStr8("yy")
.setStr9("uu")
.setStr10("ii")
.build();
System.out.println("condition2:"+condition2.toString());
}
输出:
condition1:Condition{str1='aa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
condition2:Condition{str1='aaaa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
3、也许你会说,为什么这样搞?这样搞不行吗,如下:
public static void main(String[] args) {
// 创建对象
Condition condition1 = new Condition.Builder()
.setStr1("aa")
.setStr2("bb")
.setStr3("cc")
.setStr4("dd")
.setStr5("ee")
.setStr6("rr")
.setStr7("tt")
.setStr8("yy")
.setStr9("uu")
.setStr10("ii")
.build();
System.out.println("condition1:"+condition1.toString());
Condition condition2 = condition1;
condition2.setStr1("aaaa");
System.out.println("condition2:"+condition2.toString());
}
输出:
condition1:Condition{str1='aa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
condition2:Condition{str1='aaaa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
4、好吧,我们再往下看:
public static void main(String[] args) {
// 创建对象
Condition condition1 = new Condition.Builder()
.setStr1("aa")
.setStr2("bb")
.setStr3("cc")
.setStr4("dd")
.setStr5("ee")
.setStr6("rr")
.setStr7("tt")
.setStr8("yy")
.setStr9("uu")
.setStr10("ii")
.build();
System.out.println("condition1:"+condition1.toString());
Condition condition2 = condition1;
condition2.setStr1("aaaa");
System.out.println("condition2:"+condition2.toString());
// 看这里
System.out.println("condition1:"+condition1.toString());
}
输出:
condition1:Condition{str1='aa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
condition2:Condition{str1='aaaa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
condition1:Condition{str1='aaaa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
我们发现,condition2对象修改某个属性值之后,condition1对象的属性值也变了;因为condition1和condition2虽然是内存中两个地址,但是他们指向堆中同一个对象,所以他们都对这个对象敏感
5、那怎么办?
- 先让我们的类 Condition 实现 Cloneable 接口
- 再重写 clone() 方法
public class Condition implements Cloneable{
......
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) {
// 创建对象
Condition condition1 = new Condition.Builder()
.setStr1("aa")
.setStr2("bb")
.setStr3("cc")
.setStr4("dd")
.setStr5("ee")
.setStr6("rr")
.setStr7("tt")
.setStr8("yy")
.setStr9("uu")
.setStr10("ii")
.build();
System.out.println("condition1:"+condition1.toString());
try {
Condition condition2 = (Condition)condition1.clone();
condition2.setStr1("aaaa");
System.out.println("condition2:"+condition2.toString());
System.out.println("condition1:"+condition1.toString());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
输出:
condition1:Condition{str1='aa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
condition2:Condition{str1='aaaa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
condition1:Condition{str1='aa', str2='bb', str3='cc', str4='dd', str5='ee', str6='rr', str7='tt', str8='yy', str9='uu', str10='ii'}
综上:我们通过 clone() 方法,克隆出一个新的对象,两个对象不相互影响
- 原型模式存在的问题
- 它是一种浅克隆技术(深克隆与浅克隆不在这里谈论)
- 需要为每一个类配备一个克隆方法
- 其他