Java--设计模式-14-原型模式

简介: 原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。也属于创建型模式。就是使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。也属于创建型模式。就是使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。

       这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。原型模式可以让我们不通过new来初始化对象,避免了构造函数的约束,提升了系统性能,但是也增加了系统的代码复杂性。

代码实现:

一、通过原型对象的copy方法复制一个新对象

1.创建一个接口,该接口中必须有一个可以复制本身的方法

packagecom.xing.design.prototype;
/*** 原型* @author xing*/publicinterfacePrototype {
/*** 复制本对象* @return*/Prototypecopy();
}
2.创建原型对象packagecom.xing.design.prototype;
importjava.util.ArrayList;
importjava.util.List;
/***  原型拷贝* @author xing*/publicclassPrototypeCopyimplementsPrototype{
/***  存放着必定不变的东西,也可向里面添加新东西*/privateList<String>strList;
publicPrototypeCopy() {
strList=newArrayList<>();
  }
publicPrototypeCopy(List<String>strList) {
this.strList=strList;
  }
/*** 添加新东西操作* @param str*/publicvoidaddStrToList(Stringstr) {
strList.add(str);
  }
@OverridepublicPrototypecopy() {
List<String>strLists=newArrayList<>(strList);
returnnewPrototypeCopy(strLists);
  }
@OverridepublicStringtoString() {
return"PrototypeCopy [strList="+strList+"]";
  }
}

3.编写main方法测试

packagecom.xing.design.prototype;
importjava.util.ArrayList;
importjava.util.List;
/*** 客户端* @author xing*/publicclassPrototypeDemo {
publicstaticvoidmain(String[] args) {
List<String>strList=newArrayList<>();
strList.add("不变的东西");
strList.add("复制的对象里也总有他们");
// 这里用他做原型,每一个复制的对象都会有上面这两句话,就假设他们是消耗资源的操作PrototypeCopyprototype=newPrototypeCopy(strList);
// 复制一个PrototypeCopyprototypeCopy1= (PrototypeCopy) prototype.copy();
// 再复制一个System.out.println("复制一个:"+prototypeCopy1);
PrototypeCopyprototypeCopy2= (PrototypeCopy) prototype.copy();
prototypeCopy2.addStrToList("自定义新加的");
System.out.println("再复制一个:"+prototypeCopy2);
// 基于原型的复制才意义哈,用谁来复制 谁就是原型PrototypeCopyprototypeCopy3= (PrototypeCopy) prototypeCopy2.copy();
System.out.println("再拿复制出来的复制一个:"+prototypeCopy3);
  }
}

4.测试结果

image.png

       以上结果可以看到,我们没有通过new关键字来获取对象,而是通过原型对象的copy方法成功复制了一个对象。

二、Java 的 Object 的clone()方法

       Java中lang包下的万类之王Object提供了一个clone()方法。

image.png

       clone()方法还是个native方法,native方法就是非Java语言实现的代码,供Java程序调用的,因为Java程序是运行在JVM虚拟机上面的,要想访问到比较底层的与操作系统相关的就没办法了,只能由靠近操作系统的语言来实现。

Object.clone()方法使用过程:

被复制的类(也就是原型类)需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常), 该接口为标记接口(不含任何方法),就是标记说这个类是可以复制的。

重写覆盖clone()方法,访问修饰符设为public,在方法中调用super.clone()方法得到需要的复制对象。

代码实现:

1.编写原型类

packagecom.xing.design.prototype;
importjava.util.ArrayList;
importjava.util.List;
publicclassPrototypeCopyObjimplementsCloneable{
privateStringstr;
privateList<String>strList;
publicPrototypeCopyObj() {
strList=newArrayList<>();
  }
publicPrototypeCopyObj(List<String>strList) {
this.strList=strList;
  }
publicvoidaddStrToList(Stringstr) {
strList.add(str);
  }
@OverridepublicObjectclone() {  
PrototypeCopyObjobj=null;  
try{  
obj= (PrototypeCopyObj)super.clone();  
        }catch(CloneNotSupportedExceptione) {  
e.printStackTrace();  
        }  
returnobj;  
    }  
publicStringgetStr() {
returnstr;
  }
publicvoidsetStr(Stringstr) {
this.str=str;
  }
@OverridepublicStringtoString() {
return"[strList="+strList+"]";
  }
}

2.编写main方法测试:

packagecom.xing.design.prototype;
/*** 客户端* @author xing*/publicclassPrototypeDemo {
publicstaticvoidmain(String[] args) {
// 使用Object 的clone()方法PrototypeCopyObjprototypeCopyObj=newPrototypeCopyObj();
prototypeCopyObj.addStrToList("hello");
prototypeCopyObj.addStrToList("str");
System.out.println("prototypeCopyObj:"+prototypeCopyObj);
PrototypeCopyObjprototypeCopyObj2= (PrototypeCopyObj) prototypeCopyObj.clone();
prototypeCopyObj2.addStrToList("加了一个");
System.out.println("prototypeCopyObj2:"+prototypeCopyObj2);
System.out.println("两个对象比较结果:"+(prototypeCopyObj.hashCode() ==prototypeCopyObj2.hashCode()));
System.out.println("prototypeCopyObj的hashCode:"+prototypeCopyObj.hashCode());
System.out.println("prototypeCopyObj2的hashCode:"+prototypeCopyObj2.hashCode());
  }
}


3.测试结果:

image.png

       但是这样,其实只是实现了浅拷贝。浅拷贝就是只针对普通的类型,涉及到引用类型就会出现改变新对象的引用属性同时影响到了原型对象的引用属性,这是因为浅拷贝只拷贝了引用类型的地址,并没有去新创空间。

三、验证浅拷贝时引用类型只拷贝了地址的问题

1.新建类作为原型对象的引用属性

packagecom.xing.design.prototype;
/***  原型的引用对象* @author xing*/publicclassPrototypeOther {
/***  存放着必定不变的东西,也可向里面添加新东西*/privateStringstr;
publicStringgetStr() {
returnstr;
  }
publicvoidsetStr(Stringstr) {
this.str=str;
  }
@OverridepublicStringtoString() {
return"tr= "+str;
  }
}
publicclassPrototypeCopyObjimplementsCloneable{
privateStringstr;
privateList<String>strList;
privatePrototypeOtherprototypeOther;
publicPrototypeOthergetPrototypeOther() {
returnprototypeOther;
  }
publicvoidsetPrototypeOther(PrototypeOtherprototypeOther) {
this.prototypeOther=prototypeOther;
  }
  ...

2.编写main方法测试

packagecom.xing.design.prototype;
/*** 客户端* @author xing*/publicclassPrototypeDemo {
publicstaticvoidmain(String[] args) {
// 使用Object 的clone()方法PrototypeCopyObjprototypeCopyObj=newPrototypeCopyObj();
prototypeCopyObj.addStrToList("hello");
prototypeCopyObj.addStrToList("str");
System.out.println("prototypeCopyObj:"+prototypeCopyObj);
// 测试浅拷贝弊端PrototypeOtherprototypeOther=newPrototypeOther();
prototypeOther.setStr("浅拷贝弊端就是引用类型只会改变地址,不会新创空间");
prototypeCopyObj.setPrototypeOther(prototypeOther);
PrototypeCopyObjprototypeCopyObj3= (PrototypeCopyObj) prototypeCopyObj.clone();
System.out.println("浅拷贝后引用类型的值:"+prototypeCopyObj3.getPrototypeOther().getStr());
prototypeCopyObj3.getPrototypeOther().setStr("弊端那句话改变");
System.out.println("原型引用类型的值也变成了新对象的值:"+prototypeCopyObj.getPrototypeOther().getStr());  
  }
}

3.测试结果:

image.png

       解决这个问题,就要使用深拷贝。

四、深拷贝

       深拷贝就是将引用类型的那个类也变成可复制的类。

1.实现cloneable接口并重写clone()方法:

packagecom.xing.design.prototype;
/***  原型的引用对象* @author xing*/publicclassPrototypeOtherimplementsCloneable{
/***  存放着必定不变的东西,也可向里面添加新东西*/privateStringstr;
publicStringgetStr() {
returnstr;
  }
publicvoidsetStr(Stringstr) {
this.str=str;
  }
@OverridepublicObjectclone() {  
PrototypeOtherobj=null;  
try{  
obj= (PrototypeOther)super.clone();  
        }catch(CloneNotSupportedExceptione) {  
e.printStackTrace();  
        }  
returnobj;  
    }  
@OverridepublicStringtoString() {
return"tr= "+str;
  }
}

2.在原型类中的clone方法中加上深拷贝那句:

@OverridepublicObjectclone() {  
PrototypeCopyObjobj=null;  
// 浅复制try{  
obj= (PrototypeCopyObj)super.clone();  
        }catch(CloneNotSupportedExceptione) {  
e.printStackTrace();  
        }  
// 深复制obj.prototypeOther= (PrototypeOther) prototypeOther.clone();
returnobj;  
    }

3.编写测试:

packagecom.xing.design.prototype;
/*** 客户端* @author xing*/publicclassPrototypeDemo {
publicstaticvoidmain(String[] args) {
// 使用Object 的clone()方法PrototypeCopyObjprototypeCopyObj=newPrototypeCopyObj();
prototypeCopyObj.addStrToList("hello");
prototypeCopyObj.addStrToList("str");
System.out.println("prototypeCopyObj:"+prototypeCopyObj);
// 测试浅拷贝弊端 及深拷贝PrototypeOtherprototypeOther=newPrototypeOther();
prototypeOther.setStr("浅拷贝弊端就是引用类型只会改变地址,不会新创空间");
prototypeCopyObj.setPrototypeOther(prototypeOther);
PrototypeCopyObjprototypeCopyObj3= (PrototypeCopyObj) prototypeCopyObj.clone();
System.out.println("拷贝后引用类型的值:"+prototypeCopyObj3.getPrototypeOther().getStr());
prototypeCopyObj3.getPrototypeOther().setStr("弊端那句话改变");
System.out.println("新对象引用类型的值:"+prototypeCopyObj3.getPrototypeOther().getStr());
//    System.out.println("原型对象引用类型的值也变成了新对象的值:"+prototypeCopyObj.getPrototypeOther().getStr());System.out.println("原型对象引用类型的值还是原来的值:"+prototypeCopyObj.getPrototypeOther().getStr());
  }
}


4.运行结果:

image.png

       OK!浅拷贝实现 Cloneable,重写clone()方法,深拷贝是通过实现 Serializable 读取二进制流。


总结:

       与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。逃避了构造函数的约束。在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。


END

目录
相关文章
|
11天前
|
设计模式 Java 开发者
设计模式揭秘:Java世界的七大奇迹
【4月更文挑战第7天】探索Java设计模式:单例、工厂方法、抽象工厂、建造者、原型、适配器和观察者,助你构建健壮、灵活的软件系统。了解这些模式如何提升代码复用、可维护性,以及在特定场景下的应用,如资源管理、接口兼容和事件监听。掌握设计模式,但也需根据实际情况权衡,打造高效、优雅的软件解决方案。
|
12天前
|
设计模式 存储 Java
23种设计模式,享元模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享技术有效地支持大量细粒度对象的重用。这个模式在处理大量对象时非常有用,特别是当这些对象中的许多实例实际上可以共享相同的状态时,从而可以减少内存占用,提高程序效率
30 4
|
12天前
|
设计模式 Java 中间件
23种设计模式,适配器模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】适配器模式(Adapter Pattern)是一种结构型设计模式,它的主要目标是让原本由于接口不匹配而不能一起工作的类可以一起工作。适配器模式主要有两种形式:类适配器和对象适配器。类适配器模式通过继承来实现适配,而对象适配器模式则通过组合来实现
30 4
|
16天前
|
设计模式 Java 数据库
Java设计模式精讲:让代码更优雅、更可维护
【4月更文挑战第2天】**设计模式是解决软件设计问题的成熟方案,分为创建型、结构型和行为型。Java中的单例模式确保类仅有一个实例,工厂方法模式让子类决定实例化哪个类。适配器模式则协调不兼容接口间的合作。观察者模式实现了一对多依赖,状态变化时自动通知相关对象。学习和适当应用设计模式能提升代码质量和可维护性,但需避免过度使用。设计模式的掌握源于实践与不断学习。**
Java设计模式精讲:让代码更优雅、更可维护
|
1月前
|
设计模式 安全 Java
【设计模式】原型模式
【设计模式】原型模式
|
19天前
|
设计模式 安全 Java
在Java中即指单例设计模式
在Java中即指单例设计模式
15 0
|
11天前
|
设计模式 监控 Java
设计模式 - 观察者模式(Observer):Java中的战术与策略
【4月更文挑战第7天】观察者模式是构建可维护、可扩展系统的关键,它在Java中通过`Observable`和`Observer`实现对象间一对多的依赖关系,常用于事件处理、数据绑定和同步。该模式支持事件驱动架构、数据同步和实时系统,但需注意避免循环依赖、控制通知粒度,并关注性能和内存泄漏问题。通过明确角色、使用抽象和管理观察者注册,可最大化其效果。
|
1月前
|
设计模式 存储 安全
Java设计模式---结构型模式
Java设计模式---结构型模式
|
3天前
|
设计模式 算法 Java
小谈设计模式(30)—Java设计模式总结
小谈设计模式(30)—Java设计模式总结
|
4天前
|
设计模式 存储 Java
Java设计模式:解释一下单例模式(Singleton Pattern)。
`Singleton Pattern`是Java中的创建型设计模式,确保类只有一个实例并提供全局访问点。它通过私有化构造函数,用静态方法返回唯一的实例。类内静态变量存储此实例,对外仅通过静态方法访问。
11 1