原型模式

网址链接:https://my.oschina.net/Sheamus/blog/384180

 原型模式算是JAVA中最简单的设计模式了,原因是因为它已经被提供了语言级的支持,但是如果提到它的实现原理,又是最复杂的一个设计模式。

下面我们先来看看这个又简单又复杂的设计模式的定义。

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

定义比较简单,总结一下是通过实例指定种类,通过拷贝创建对象。

在JAVA语言中使用原型模式是非常简单的,这是因为Object类当中提供了一个本地方法clone,而JAVA中的任何类只要实现了Cloneable标识接口,就可以使用clone方法来进行对象的拷贝。

 我们写一个简单的实例来测试一下,很简单。
 

public class Prototype implements Cloneable {

        private int x;

        private int y;

        private int z;

        public Prototype() {

                this.x = 2;

                this.y = 3;

                this.z = 4;

        }

        public void change() {

                this.x = 9;

                this.y = 8;

                this.z = 7;

        }

        public Prototype clone() {

                Object object = null;

                try {

                        object = super.clone();

                } catch (CloneNotSupportedException exception) {

                        throw new RuntimeException(exception);

                }

                return (Prototype) object;

        }

        public String toString() {

                return "[" + x + "," + y + "," + z + "]";

        }

        public static void main(String[] args) {

                Prototype prototype1 = new Prototype();

                prototype1.change();

                System.out.println(prototype1);

                Prototype prototype2 = prototype1.clone();

                System.out.println(prototype2);

        }

}

输出结果:

[9,8,7]

[9,8,7]        

       从输出结果可以看出来,clone方法将prototype1复制了一个,然后赋给了prototype2,这就像复制粘贴一样。值得注意的是,在使用Object.clone()方法去拷贝一个对象时,构造方法是不被执行的,否则prototype2实例中x,y,z的值应该为2,3,4才对,如果你觉得不够直观,可以在构造方法里写一个输出语句试试。

从原型模式的使用方式不难推断出,原型模式常使用于以下场景:

       1、对象的创建非常复杂,可以使用原型模式快捷的创建对象。

       2、在运行过程中不知道对象的具体类型,可使用原型模式创建一个相同类型的对象,或者在运行过程中动态的获取到一个对象的状态。

对于clone方法,它执行的是浅拷贝,也就是说如果是引用类型的属性,则它不会进行拷贝,而是只拷贝引用。

       看下面这个简单的测试,就能看出来了。

class Field{

        private int a;

        public int getA() {

                return a;

        }

        public void setA(int a) {

                this.a = a;

        }

       

}



public class ShallowPrototype implements Cloneable {

        private int x;

        private int y;

        private int z;

        private Field field;

        public ShallowPrototype() {

                this.x = 2;

                this.y = 3;

                this.z = 4;

                this.field = new Field();

                this.field.setA(5);

        }

       

        public Field getField() {

                return field;

        }

        public ShallowPrototype clone() {

                Object object = null;

                try {

                        object = super.clone();

                } catch (CloneNotSupportedException exception) {

                        throw new RuntimeException(exception);

                }

                return (ShallowPrototype) object;

        }

        public String toString() {

                return "[" + x + "," + y + "," + z + "," + field.getA() + "]";

        }

        public static void main(String[] args) {

                ShallowPrototype prototype1 = new ShallowPrototype();

                System.out.println(prototype1);

                System.out.println(prototype1.getField());

                ShallowPrototype prototype2 = prototype1.clone();

                System.out.println(prototype2);

                System.out.println(prototype2.getField());

        }

}

输出结果:

[2,3,4,5]

com.prototype.Field@de6ced

[2,3,4,5]

com.prototype.Field@de6ced

        可以看到我们对ShallowPrototype拷贝以后,得到一个实例prototype2,不过当我们输出field属性时,发现它们是引用的同一个对象。这当然不是我们期望得到的结果,这种情况下,我们如果修改prototype1中field的属性a的值,则prototype2中的也会跟着改变。

       然而如果要实现深度拷贝,则需要将实现了Cloneable接口并重写了clone方法的类中,所有的引用类型也全部实现Cloneable接口并重写clone方法,而且需要将引用类型的属性全部拷贝一遍。

      下面是一个简单的深度拷贝的例子,由上面的例子更改得到。

class Field implements Cloneable{       

        private int a;

        public int getA() {

                return a;

        }

        public void setA(int a) {

                this.a = a;

        }

       

        protected Field clone() {

                Object object = null;

                try {

                        object = super.clone();

                } catch (CloneNotSupportedException exception) {

                        throw new RuntimeException(exception);

                }

                return (Field) object;

        }

       

}



public class DeepPrototype implements Cloneable {

        private int x;

        private int y;

        private int z;

        private Field field;

        public DeepPrototype() {

                this.x = 2;

                this.y = 3;

                this.z = 4;

                this.field = new Field();

                this.field.setA(5);

        }

       

        public Field getField() {

                return field;

        }

        protected DeepPrototype clone() {

                Object object = null;

                try {

                        object = super.clone();

                        ((DeepPrototype)object).field = this.field.clone();

                } catch (CloneNotSupportedException exception) {

                        throw new RuntimeException(exception);

                }

                return (DeepPrototype) object;

        }

        public String toString() {

                return "[" + x + "," + y + "," + z + "," + field.getA() + "]";

        }

        public static void main(String[] args) {

                DeepPrototype prototype1 = new DeepPrototype();

                System.out.println(prototype1);

                System.out.println(prototype1.getField());

                DeepPrototype prototype2 = prototype1.clone();

                System.out.println(prototype2);

                System.out.println(prototype2.getField());

        }

}

输出结果:

[2,3,4,5]

com.prototype.Field@a90653

[2,3,4,5]

com.prototype.Field@de6ced

 

下面我们来看下原型模式的主要优点:

        1、由于clone方法是由虚拟机直接复制内存块执行,所以在速度上比使用new的方式创建对象要快。

        2、可以基于原型,快速的创建一个对象,而无需知道创建的细节。

        3、可以在运行时动态的获取对象的类型以及状态,从而创建一个对象。

然而原型模式的缺点也是相当明显的,主要的缺点就是实现深度拷贝比较困难,需要很多额外的代码量。

       不过实际当中我们使用原型模式时,也可以写一个基类实现Cloneable接口重写clone方法,然后让需要具有拷贝功能的子类继承自该类,这是一种节省代码量的常用方式。像上面的例子一样,如果一个类继承自Prototype,则会自动具有拷贝功能。

关于 阿里云盘CLI。仿 Linux shell 文件处理命令的阿里云盘命令行客户端,支持JavaScript插件,支持同步备份功能,支持相册批量下载。 特色 多平台支持, 支持 Windows, macOS, linux(x86/x64/arm), android, iOS 等 阿里云盘多用户支持 支持备份盘,资源库无缝切换 下载网盘内文件, 支持多个文件或目录下载, 支持断点续传和单文件并行下载。支持软链接(符号链接)文件。 上传本地文件, 支持多个文件或目录上传,支持排除指定文件夹/文件(正则表达式)功能。支持软链接(符号链接)文件。 同步备份功能支持备份本地文件到云盘,备份云盘文件到本地,双向同步备份保持本地文件和网盘文件同步。常用于嵌入式或者NAS等设备,支持docker镜像部署。 命令和文件路径输入支持Tab键自动补全,路径支持通配符匹配模式 支持JavaScript插件,你可以按照自己的需要定制上传/下载中关键步骤的行为,最大程度满足自己的个性化需求 支持共享相册的相关操作,支持批量下载相册所有普通照片、实况照片文件到本地 支持多用户联合下载功能,对下载速度有极致追求的用户可以尝试使用该选项。详情请查看文档多用户联合下载 如果大家有打算开通阿里云盘VIP会员,可以使用阿里云盘APP扫描下面的优惠推荐码进行开通。 注意:您需要开通【三方应用权益包】,这样使用本程序下载才能加速,否则下载无法提速。 Windows不第二步打开aliyunpan命令行程序,任何云盘命令都有类似如下日志输出 如何登出和下线客户端 阿里云盘单账户最多只允许同时登录 10 台设备 当出现这个提示:你账号已超出最大登录设备数量,请先下线一台设备,然后重启本应用,才可以继续使用 说明你的账号登录客户端已经超过数量,你需要先登出其他客户端才能继续使用,如下所示
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值