Java设计模式之原型模式
时间隔了好几天了,今天写一下设计模式中的原型模式,示例代码几天前已经瞧好了,想做一些优化,方便大家对这个模式的理解更加深入一点,另外也需要找更多详细点的资料
一 : 含义 什么是原型模式 ?
使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。
二 : 解决的问题
多个相同对象重复创建的较大开销
三: 模式原理
3.1模式的结构
Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至可以说具体实现类。
ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个原型对象,在通过调用搞对象的克隆方法即可得到多个相同的对象。由于客户端针对抽象原型类Prototype编程,因此用户可以根据需要选择具体原型类,系统具有较好的可扩展性,增加或更换具体原型类都很方便。
原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件 :
- 实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
- 重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型
四 实现代码
步骤一 : 原型
@Data
public class MonkeySun implements Cloneable {
private String name;
private String weapon;
@Override
protected Object clone(){
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
System.out.println("悟空分身失败");
}
return clone;
}
}
步骤二 : 测试
public class PrototypeTest {
public static void main(String[] args) {
MonkeySun monkeySun = new MonkeySun();
monkeySun.setName("孙悟空");
monkeySun.setWeapon("金箍棒");
System.out.println("原型 : " + monkeySun + " hashcode : " +monkeySun.hashCode());
MonkeySun clone = (MonkeySun) monkeySun.clone();
clone.setName("孙行者");
clone.setWeapon("阴阳瓶");
System.out.println("克隆 : " + clone + " hashcode : " +clone.hashCode());
}
克隆产生的新的对象
在下面孙悟空又学习了新的术法神通.地煞七十二变
悟空实体:
@Data
public class MonkeySun implements Serializable,Cloneable {
private String name;
private String weapon;
private Magic magic;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
神通类:
@Data
public class Magic{
private String name;
public Magic() {
}
public Magic(String name) {
this.name = name;
}
}
练习:
MonkeySun monkeySun = new MonkeySun();
monkeySun.setMagic(new Magic("三头流弊"));
monkeySun.setName("孙悟空");
monkeySun.setWeapon("金箍棒");
System.out.println("原型 : " + monkeySun + monkeySun.hashCode());
MonkeySun clone = (MonkeySun) monkeySun.clone();
System.out.println("克隆 : " + clone + clone.hashCode());
monkeySun.getMagic().setName("地煞七十二变");
System.out.println("原型 : " + monkeySun + monkeySun.hashCode());
System.out.println("克隆 : " + clone + clone.hashCode());
测试 :
原型 : MonkeySun(name=孙悟空, weapon=金箍棒, magic=Magic(name=三头流弊))-2098436648
克隆 : MonkeySun(name=孙悟空, weapon=金箍棒, magic=Magic(name=三头流弊))-2098436648
原型 : MonkeySun(name=孙悟空, weapon=金箍棒, magic=Magic(name=地煞七十二变))-2015179652
克隆 : MonkeySun(name=孙悟空, weapon=金箍棒, magic=Magic(name=地煞七十二变))-2015179652
发生了一点奇怪的事情,悟空的原型学了七十二变,分身自然也学会了,实际中并没有这么bug的,原型产生改变,克隆的对象应该是独立个体,不涉及改变的.由此就引入原型模式的一个概念,浅克隆
浅克隆 : 创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
那么该怎样实现深克隆达到这种无关性呢?
答案很简单,子对象同样实现clone的相关接口,同时原型类增加该对象的返回
@Data
public class Magic implements Cloneable{
private String name;
public Magic() {
}
public Magic(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
原型对象返回:
@Data
public class MonkeySun implements Cloneable {
private String name;
private String weapon;
private Magic magic;
@Override
protected Object clone() throws CloneNotSupportedException {
MonkeySun monkeySun = (MonkeySun)super.clone();
monkeySun.magic = (Magic) this.magic.clone();
return monkeySun;
}
}
测试 :
public static void main(String[] args) throws CloneNotSupportedException {
MonkeySun monkeySun = new MonkeySun();
monkeySun.setMagic(new Magic("三头流弊"));
monkeySun.setName("孙悟空");
monkeySun.setWeapon("金箍棒");
System.out.println("原型 : " + monkeySun + monkeySun.hashCode());
MonkeySun clone = (MonkeySun) monkeySun.clone();
System.out.println("克隆 : " + clone + clone.hashCode());
monkeySun.getMagic().setName("地煞七十二变");
System.out.println("原型 : " + monkeySun + monkeySun.hashCode());
System.out.println("克隆 : " + clone + clone.hashCode());
}
结果展示 :
原型 : MonkeySun(name=孙悟空, weapon=金箍棒, magic=Magic(name=三头流弊))-2098436648
克隆 : MonkeySun(name=孙悟空, weapon=金箍棒, magic=Magic(name=三头流弊))-2098436648
原型 : MonkeySun(name=孙悟空, weapon=金箍棒, magic=Magic(name=地煞七十二变))-2015179652
克隆 : MonkeySun(name=孙悟空, weapon=金箍棒, magic=Magic(name=三头流弊))-2098436648
另外关于深克隆还是一种通过序列化的方式实现的,想了解的小伙伴可以通过其他途径来了解一下
五 总结 :
应用场景 :
原型模式的单独运用场景并不是很多,一般都是搭配其他实际模式一起使用的
对原型模式的学习就记录这么多,如果对大家有帮助的话,可以点一个赞哈,你的鼓励也是创作的动力.共同在计算机的世界加油吧 !