(五)原型模式(Prototype)
最后更新于:2022-04-01 15:48:14
原型模式就是通过一个原型对象来表明要创建的对象类型,然后用复制这个原型对象的方法来创建更多同类型的对象。
自己对原型模式简单理解的原理图如下:
具体属性没有添加:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_578455ccc8ed4.png)
原型模式里面关键点就在一个Cloneable接口和clone方法的重写
下面就通过一个配钥匙的例子简单的写了一个程序,起初一个一个抽象类,这样可以重写clone方法,如果是接口的话就得到子类里面把重写的方法具体声明,这样的话对于程序的复用性不是很好,于是就写了一个抽象的类KeyPrototype然后,写了两个子类继承一个客户端,代码如下:
~~~
package com.designpattern.prototype;
public abstract class KeyPrototype implements Cloneable {
private String color;
private float length;
private float thick;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return this.getClass() + " -> Color:" + this.getColor() + " Length:"
+ this.getLength() + " Thick:" + this.getThick();
}
public String getColor() {
return color;
}
public float getLength() {
return length;
}
public float getThick() {
return thick;
}
public void setColor(String color) {
this.color = color;
}
public void setLength(float length) {
this.length = length;
}
public void setThick(float thick) {
this.thick = thick;
}
}
~~~
~~~
package com.designpattern.prototype;
public class CopperKey extends KeyPrototype {
}
~~~
~~~
package com.designpattern.prototype;
public class AluminiumKey extends KeyPrototype {
}
~~~
~~~
package com.designpattern.prototype;
public class Client {
public static void main(String[] args) {
KeyPrototype copperkey = new CopperKey();
copperkey.setColor("red");
copperkey.setLength(12);
copperkey.setThick(2);
System.out.println(copperkey);
try {
KeyPrototype aluminaumkey = (KeyPrototype) copperkey.clone();
aluminaumkey.setColor("yellow");
aluminaumkey.setLength(10);
aluminaumkey.setThick(5);
System.out.println(aluminaumkey);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
~~~
~~~
class com.designpattern.prototype.CopperKey -> Color:red Length:12.0 Thick:2.0
class com.designpattern.prototype.CopperKey -> Color:yellow Length:10.0 Thick:5.0
~~~
这样就简单对前者进行的复制,很显然他们并不是一个对象,里面关于clone的东西做了一个简单的总结
同时来证明他们确实是两个对象,就是改动里面的属性不互相影响:
首先我创建了一个Dog类
~~~
package com.note.clone;
public class Dog/* implements Cloneable */{
private String color;
private String name;
public Dog(String name,String color){
this.name = name;
this.color = color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/* @Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}*/
@Override
public String toString() {
return this.getClass()+" "+this.getName()+" "+this.getColor();
}
}
~~~
然后写了一个Tom类,其中Tom类里面有私有属性Dog
~~~
package com.note.clone;
public class Tom implements Cloneable {
private String color;
private Dog dog = new Dog("mimi", "yellow");;
private String name;
@Override
protected Object clone() throws CloneNotSupportedException {
Tom o = null;
o = (Tom)super.clone();
// o.setDog((Dog)o.getDog().clone());
return o;
}
public String getColor() {
return color;
}
public Dog getDog() {
return dog;
}
public String getName() {
return name;
}
public void setColor(String color) {
this.color = color;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return this.getClass() + " " + this.getName() + " " + this.getColor()
+ "\n" + "Dog:" + this.dog;
}
}
~~~
然后写了一个People类简单的对上述的两个程序进行测试:
~~~
package com.note.clone;
public class People {
public static void main(String[] args) {
Tom tom = new Tom();
tom.setName("Tom");
tom.setColor("blue");
System.out.println(tom);
System.out.println();
try {
Tom tylo = (Tom) tom.clone();
tylo.setName("tylo");
tylo.setColor("red");
tylo.getDog().setName("lucky");
tylo.getDog().setColor("green");
System.out.println(tylo);
System.out.println();
System.out.println(tom);
System.out.println();
Dog dog = tylo.getDog();
dog.setName("hello");
dog.setColor("white");
System.out.println(tylo);
System.out.println();
System.out.println(tom);
System.out.println();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
~~~
运行结果如下:
~~~
class com.note.clone.Tom Tom blue
Dog:class com.note.clone.Dog mimi yellow
class com.note.clone.Tom tylo red
Dog:class com.note.clone.Dog lucky green
class com.note.clone.Tom Tom blue
Dog:class com.note.clone.Dog lucky green
class com.note.clone.Tom tylo red
Dog:class com.note.clone.Dog hello white
class com.note.clone.Tom Tom blue
Dog:class com.note.clone.Dog hello white
~~~
这样很明确的表明了对于这两个对象的属性,自己的属性除了Dog以外都是自己的,没有对着对方的属性的改变而改变,但是Dog属性,两个对象的属性是一样的
那么这里就到了深度克隆
我们把Dog和Tom里注释掉的内容打开再运行People程序,运行结果如下:
~~~
class com.note.clone.Tom Tom blue
Dog:class com.note.clone.Dog mimi yellow
class com.note.clone.Tom tylo red
Dog:class com.note.clone.Dog lucky green
class com.note.clone.Tom Tom blue
Dog:class com.note.clone.Dog mimi yellow
class com.note.clone.Tom tylo red
Dog:class com.note.clone.Dog hello white
class com.note.clone.Tom Tom blue
Dog:class com.note.clone.Dog mimi yellow
~~~
很明显发现,两个对象的Dog属性也没有互相影响,说明了他们不是用的一个引用,这样也证明了上面的例子,他们分别是一个对象,达到了克隆复用的应用。
在原型模式中,可以动态的添加产品分类,而且对整体结构没有影响。
由于原型模式需要给每一个类都配备一个克隆方法,这就需要在这几类的时候通盘考虑,因为在已有类的基础上来添加clone操作时比较困难的,而且原型模式在实现深层的复制时,需要编写一定量的代码。