浅学设计模式之原型模式 (3/23)

网友投稿 556 2022-11-17

浅学设计模式之原型模式 (3/23)

浅学设计模式之原型模式 (3/23)

1、原型模式的概念

原型模式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

关键词就是:拷贝

我们最开始会构造(去实现其细节)一个实例,如果后面我们还需要去构建一个和这个实例一模一样、另一个新的实例,我们无需再和原来一样去实现其细节,而是通过原型模式直接拷贝。

2、原型模式的使用场景及UML图

举个最简单的例子吧,我们在找工作的时候需要准备很多份简历。 我们通过构思,准备出了第一份简历,然后后面的简历都是对这个进行拷贝了。

如果自己实现,在原始情况下是这样的:

/** * 简历类 ,里面是简历的信息**/public class Resume { private String name; private String sex; private String age; private String experience; public Resume(String name, String sex, String age, String experience) { this.name = name; this.sex = sex; this.age = age; this.experience = experience; } ...}/** * Main函数,客户端使用**/ public void main(){ Resume a = new Resume("小a","男","21","应届生"); Resume b = new Resume("小a","男","21","应届生"); Resume c = new Resume("小a","男","21","应届生"); Resume d = new Resume("小a","男","21","应届生"); }

通过copy+paste,我们这样打印出了所有的简历。

但是这种原始的方法有它的缺点:

如果要复制很多的话,代码会显得很臃肿因为假如构造信息很多,则通过复制+粘贴出来的代码可读性会降低,但是开了for循环会好一点如果不开for循环,万一手动实现的时候中间有那么一两个实例的参数敲错了,那检查起来将会很费劲。万一,我们突然失忆了,忘记了最开始实例(即实例a)的参数,比如我年龄记成22了,我之后也打22,或者说,我根本就不知道原型的参数,它对我们不公开,但是我们却要去复制它,这不就难办了么。

而如果Resume类有一个​​clone()​​方法,通过类类似:

Resume b = a.clone();

的代码来进行克隆,则我们不需要知道要拷贝实例的参数(即细节),就能复制n份实例出来。

而这也是原型模式的实现原理。

原型模式UML图如下:

根据UML图,我们需要先把Prototype原型类给建立出来:

//Protype原型类public abstract class ResumeProtoType { private String name; public ResumeProtoType(String name) { this.name = name; } public abstract ResumeProtoType cloneThis();}

然后在实体类里构造并实现克隆方法:

//concreteProtoType1public class MyResume extends ResumeProtoType { public MyResume(String name) { super(name); } @Override public ResumeProtoType cloneThis() { return (MyResume)this; }}

最后再在客户端代码中取通过cloneThis()创建一个实例:

//Client层 MyResume p1 = new MyResume("小a"); MyResume p2 = (MyResume) p1.cloneThis();

那这样通过​​cloneThis()​​就能够疯狂拷贝了。

3、Java中的原型模式

因为在Java中,克隆拷贝实在是太常用了,所以JDK自带了克隆​​接口 Cloneable​​​,​​Object也有自己实现了clone()​​​,所以,当我们使用了这个接口或者个方法的时候,我们已经在原型模式中了。 此时的UML图如下:

来看代码:

//直接的实现类并重写clone方法public class MyResume implements Cloneable { String name; public MyResume(String name) { this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }}

然后客户端代码如下:

= new MyResume("小a"); try { MyResume p2 = p1.clone(); Log.d(TAG, p2.toString()); } catch (CloneNotSupportedException e) { e.printStackTrace(); }

打印出来为:

但是看到这里也不要高兴的太早,因为这样的复制其实并不算是完全的克隆,它只是一种浅复制。

4、浅复制与深复制

上述的MyResume里面的字段只是普通的String,如果我们在里面加一个实体类成员呢,比如我们写出一个Company类:

public class Company { String companyName; ...}

并将其加入到MyResume中:

public class MyResume implements Cloneable { String name; Company company; public MyResume(String name, Company company) { this.name = name; this.company = company; } public void setCompanyName(String name) { this.company.companyName = name; } ....}

这个时候我们再去进行clone,并且在克隆后更改一下信息:

= new MyResume("小a", new Company("Tencent")); try { MyResume p2 = p1.clone(); //我们更改一下p2的公司名称 p2.setCompanyName("ALi"); Log.d(TAG, p1.toString() + " \n " + p2.toString()); } catch (CloneNotSupportedException e) { e.printStackTrace(); }

这个时候在打印出来看看:

这个时候发现,p1的名称居然也被改了,这显然不是我们想要的。

被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他的对象的引用都仍然指向原来的对象,这就是浅复制 所以companyName指向了同一个引用。最后改的会显示出来。

一句话概括为:如果一个类想要实现深复制,那么其里面的所有成员也要实现Cloneable接口,即所有成员都要序列化。

UML图如下:

所以我们需要让Company来实现Cloneable:

public class Company implements Cloneable{ ... @Override protected Company clone() throws CloneNotSupportedException { return (Company) super.clone(); }}

然后还需要在Resume进行拷贝的时候,让自己的Company也来拷贝一下!这样相当于全部拷贝了而不是借过来用。

public class MyResume implements Cloneable { ... @Override public MyResume clone() throws CloneNotSupportedException { MyResume myResume = null; myResume = (MyResume) super.clone(); myResume.company = company.clone(); return myResume; }}

客户端代码一样,最后的结果为:

OK,这样就得出了我们想要的结果了。

结论

原型模式的概念就是创建一个原型A,通过拷贝A可以得到B、C…特点是拷贝的过程中我们不需要知道原型类的细节(参数、方法),而实现了全面拷贝是创建型的模式,它也能创建出一个全新的类。在Java中,一个类实现了​​Cloneable接口​​​重写​​clone()​​方法,那么这就是一个原型模式,所以我们平时不用太去在意这个模式。因为有浅复制和深复制的概念,所以在让一个类实现Cloneable后,也要让其内部的对象也都实现​​Cloneable​​接口,这样才能完全拷贝。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Docker基础(一)
下一篇:Android 开发艺术探索笔记(15)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~