设计模式之原型模式
原型模式--导读
生活中我们经常碰到那种需要复制的时候,比如说当我们需要在写一篇又长又难写的文章时,我们第一时间想的便是在网上找到一篇相对应的文章直接进行复制即可。这样不仅可以省很多时间同样还可以省下很多精力,但是当我们要写一篇很复杂的文章时,我们也想的是复制,但是相对应的问题来了,我们想要复制也要找到一篇相对应的文章来复制,当文章的结构很复杂的时候我们还需要了解其中的结构选择性的复制,这样就很麻烦了。所以我们便想到创建一个原型,然后我们只需要相对应的类型后,这个原型便会自己进行复制,最后我们便可以直接获取一个想要的对象,这便是原型模式。在原型模式中我们可以利用一个原型对象指明我们需要对象类型,然后通过复制方法,获取与该对象一模一样的对象实例。
原型模式--定义
通过前面的导读我们就可以基本确定原型模式的定义------原型模式就是利用指定的对象类型,通过复制来获得一个新的实例对象。在原型模式中,所发动创建的对象通过请求原型对象来拷贝原型对象自己来实现创建过程,当然所发动创建的对象需要知道原型对象的类型。这里也就是说我们创建新对象是只需要知道相对对象类型,
便可已创建一个新的实例对象,至于这些原型对象时如何创建的根本不需要关心。
原型模式--结构
下图是原型模式的UML结构图:
原型模式主要包含如下三个角色:
Prototype:抽象原型类。声明克隆自身的接口。
ConcretePrototype:具体原型类。实现克隆的具体操作。
Client:客户类。让一个原型克隆自身,从而获得一个新的对象。
原型模式--代码实现
我们都知道java中所有的类都是继承自object,而object提供一个clone方法来供我们使用,但是使用该方法需要实现Cloneable接口否则直接使用clone会抛出CloneNotSupportedException异常。
下面我以克隆技术为例实现原型模式:
animal.java定义所有原型的抽象类
package Prototype_Pattern; /** * 定义所有要克隆动物的抽象类 * @author liu * */ public abstract class Animal implements Cloneable { public String type; public String color; public String sex; public String getType() { return type; } public void setType(String type) { this.type = type; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Object clone() { Animal a=null; try { a=(Animal)super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return a; } public abstract void barking(); @Override public String toString() { return "Animal [type=" + type + ", color=" + color + ", sex=" + sex + "]"; } }
SheepDuoLi.java实现父类的实体类,需要复制的原型
package Prototype_Pattern; public class SheepDuoLi extends Animal { public SheepDuoLi() { this.type="多利羊"; } @Override public void barking() { System.out.println("咩咩咩"); } }
client.java客户端,客户端只需要知道原型是什么类型,便可实现复制,实现原型与客户端之间的解耦
package Prototype_Pattern; public class client { public static void main(String[] args) { //创建出一个原型 SheepDuoLi duoli=new SheepDuoLi(); duoli.setColor("白色"); duoli.setSex("雄"); SheepDuoLi s=(SheepDuoLi)duoli.clone(); System.out.println("原型羊"); System.out.println(duoli.toString()); System.out.println("克隆羊"); System.out.println(s.toString()); System.out.println("是否是同一个对象"); //俩个对象之间地址不同说明两对象不同 System.out.println(s==duoli); } }
原型模式---优缺点
优点:
①原型模式向客户隐藏了创建新实例的复杂性
②原型模式允许动态增加或较少产品类。
③原型模式简化了实例的创建结构,工厂方法模式需要有一个与产品类等级结构相同的等级结构,而原型模式不需要这样。
④产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构
缺点:
①每个类必须配备一个克隆方法
②配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
原型模式--使用场景
1、资源优化场景。
2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
3、性能和安全要求的场景。
4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
5、一个对象多个修改者的场景。
6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用
原型模式--拓展
讲到原型模式就不得不谈一谈深复制和浅复制了。
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。
pos:当前对象的地址;
son:son属性所指向的地址;
name:对象的name属性。
由上图可知浅克隆对于对象引用并没有改变,而深克隆对对象的引用改变了,同时我们也可以之到上述原型模式例子中只是简单的使用clone方法
并没有实现深克隆