原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在软件系统中,有时候需要多次创建某一类型的对象,为了简化创建过程,可以只创建一个对象,然后再通过克隆的方式复制出多个相同的对象,这就是原型模式的设计思想。
原型模式的基本工作原理是通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象复制原型自己来实现创建过程。
举例说明 👇
《西游记》中孙悟空拔毛变小猴的故事几乎人人皆知,孙悟空可以用猴毛根据自己的形象,复制出很多跟自己长得一模一样的身外身来。
孙悟空这种复制出多个身外身的方式在面向对象设计领域里称为原型(Prototype)模式。在面向对象系统中,使用原型模式来复制一个对象自身,从而克隆出多个与原型对象一模一样的对象
。
在软件系统中,有些对象的创建过程较为复杂,而且有时候需要频繁创建。原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在。
原型模式包含如下角色 👇
抽象原型类是定义具有克隆自己的方法的接口,是所有具体原型类的公共父类,可以是抽象类,也可以是接口。
具体原型类实现具体的克隆方法,在克隆方法中返回自己的一个克隆对象。
客户类让一个原型克隆自身,从而创建一个新的对象。在客户类中只需要直接实例化或通过工厂方法等方式创建一个对象,再通过调用该对象的克隆方法复制得到多个相同的对象。
原型模式的克隆分为浅克隆和深克隆。
下面通过两个分别实现浅克隆和深克隆的实例来进一步学习并理解原型模式。
Object作为抽象原型类,在Java语言中,所有的类都是Object的子类,在Object 中提供了克隆方法clone(),用于创建一个原型对象,其 clone()方法具体实现由JVM完成,用户在使用时无须关心。
为了更好地说明浅克隆和深克隆的区别,在本实例中引入了附件类Attachment,邮件类Email与附件类是组合关联关系,在邮件类中定义一个附件类对象,作为其成员对象。
package prototype;
/** * @author mengzhichao * @create 2021-11-10-22:20 */
public class Attachment {
public void download(){
System.out.println("下载附件");
}
}
Email类是具体原型类,也是Object类的子类。在Java语言中,只有实现了Cloneable接口的类才能够使用clone()方法来进行复制,因此Email类实现了Cloneable接口。在Email类中覆盖了Object的clone()方法,通过直接或者间接调用Object的clone()方法返回一个克隆的原型对象。在Email类中定义了一个成员对象attachment,其类型为Attachment。
package prototype;
/** * @author mengzhichao * @create 2021-11-10-22:18 */
public class Email implements Cloneable {
private Attachment attachment=null;
public Email(){
this.attachment=new Attachment();
}
@Override
public Object clone(){
Email clone =null;
try {
clone=(Email) super.clone();
}catch (CloneNotSupportedException e){
System.out.println("Clone failure!");
}
return clone;
}
public Attachment getAttachment(){
return this.attachment;
}
public void display(){
System.out.println("查看邮件");
}
}
在Client 客户端测试类中,比较原型对象和复制对象是否一致﹐并比较其成员对象attachment的引用是否一致。
package prototype;
/** * @author mengzhichao * @create 2021-11-10-22:29 */
public class Client {
public static void main(String[] args) {
Email email,copyEmail;
email=new Email();
copyEmail= (Email) email.clone();
System.out.println("email == copyEmail?");
System.out.println(email == copyEmail);
System.out.println("email.getAttachment() == copyEmail.getAttachment()?");
System.out.println(email.getAttachment() == copyEmail.getAttachment());
}
}
结果如下
使用深克隆实现邮件复制,即复制邮件的同时复制附件。
作为Email类的成员对象,在深克隆中,Attachment类型的对象也将被写入流中,因此Attachment类也需要实现Serializable接口。
package prototype2;
import java.io.Serializable;
/** * @author mengzhichao * @create 2021-11-10-22:20 */
public class Attachment implements Serializable {
public void download(){
System.out.println("下载附件");
}
}
Email作为具体原型类,由于实现的是深克隆,无须使用Object的 clone()方法,因此无须实现Cloneable接口;可以通过序列化的方式实现深克隆(代码中粗体部分),由于要将Email类型的对象写入流中,因此Email类需要实现Serializable接口。
package prototype2;
import java.io.*;
/** * @author mengzhichao * @create 2021-11-10-22:18 */
public class Email implements Serializable {
private Attachment attachment=null;
public Email(){
this.attachment=new Attachment();
}
public Object deepClone() throws IOException,ClassNotFoundException, OptionalDataException{
//将对象写入流中
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ObjectOutputStream oos =new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象从流中取出
ByteArrayInputStream bis =new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois =new ObjectInputStream(bis);
return (ois.readObject());
}
public Attachment getAttachment(){
return this.attachment;
}
public void display(){
System.out.println("查看邮件");
}
}
在Client客户端测试类中,我们仍然比较深克隆后原型对象和拷贝对象是否一致,并比较其成员对象attachment的引用是否一致。
package prototype2;
/** * @author mengzhichao * @create 2021-11-11-22:28 */
public class Client {
public static void main(String[] args) {
Email email,copyEmail = null;
email=new Email();
try {
copyEmail = (Email) email.deepClone();
}catch (Exception e){
e.printStackTrace();
}
System.out.println("email==copyEmail?");
System.out.println(email==copyEmail);
System.out.println("email.getAttachment()==copyEmail.getAttachment()?");
System.out.println(email.getAttachment()==copyEmail.getAttachment());
}
}
通过结果可以看出,表达式( email==copyEmail)结果为false,即通过复制得到的对象与原型对象的引用不一致,表达式( email.getAttachment()==copyEmail.getAttachment())结果也为false,原型对象与克隆对象对成员对象的引用不相同,说明其成员对象也复制了一份。
原型管理器(Prototype Manager)角色创建具体原型类的对象,并记录每一个被创建的对象。原型管理器的作用与工厂相似,其中定义了一个集合用于存储原型对象,如果需要某个对象的一个克隆,可以通过复制集合中对应的原型对象来获得。在原型管理器中针对抽象原型类进行编程,以便扩展。
下面使用代码模拟演示一个颜色原型管理器的实现过程。
package prototypemanager;
/** * @author mengzhichao * @create 2021-11-14-10:30 */
public interface MyColor extends Cloneable {
public Object clone();
public void display();
}
package prototypemanager;
/** * @author mengzhichao * @create 2021-11-14-10:32 */
public class Red implements MyColor {
@Override
public Object clone() {
Red r=null;
try {
r = (Red) super.clone();
}catch (Exception e){
}
return r;
}
@Override
public void display() {
System.out.println("This is Red");
}
}
package prototypemanager;
/** * @author mengzhichao * @create 2021-11-14-10:36 */
public class Blue implements MyColor {
@Override
public Object clone() {
Blue b=null;
try {
b = (Blue) super.clone();
}catch (Exception e){
}
return b;
}
@Override
public void display() {
System.out.println("This is Blue");
}
}
package prototypemanager;
import java.util.Hashtable;
/** * @author mengzhichao * @create 2021-11-14-10:37 */
public class PrototypeManager {
private Hashtable ht =new Hashtable();
public PrototypeManager() {
ht.put("red",new Red());
ht.put("blue",new Blue());
}
public void addColor(String key,MyColor obj){
ht.put(key,obj);
}
public MyColor getColor(String key){
return (MyColor) ((MyColor)ht.get(key)).clone();
}
}
package prototypemanager;
/** * @author mengzhichao * @create 2021-11-14-10:47 */
public class Client {
public static void main(String[] args) {
PrototypeManager pm =new PrototypeManager();
MyColor obj1=pm.getColor("red");
obj1.display();
MyColor obj2=pm.getColor("red");
obj2.display();
System.out.println(obj1==obj2);
}
}
运行结果如下
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_45692705/article/details/121257205
内容来源于网络,如有侵权,请联系作者删除!