原型模式
-
作用:用原型实例指定创建对象的种类,并且通过复制(克隆)这些原型创建新的对象。
-
使用频率:不常用,使用场景非常少。
-
特点:通过克隆的方式创建对象。
-
境界:写代码的最高境界就是crtl+c/v,建立自己的技术平台,复用代码,修改代码。
-
关键点:
- 抽象原型类:它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至可以是具体实现类。
- 具体原型类:它实现抽象原型类中声明的方法,在克隆方法中返回自己的一个克隆对象。
- 客户类:具体原型对象克隆自身从而创建一个全新的对象。
-
使用场景:构造函数复杂,这样通过new来创建对象需要非常繁琐的数据准备。
-
举例
-
简历:将一份简历,复制多次,得到多份简历。
-
代码示例:
-
Resume:
package com.prototype; public interface Resume { public Resume clone(); }
-
ConcreteResume
package com.prototype; public class ConcreteResume implements Resume { @Override public Resume clone() { Resume re = new ConcreteResume(); return re; } }
-
Client
package com.prototype; public class Client { public static void main(String[] args) { Resume re = new ConcreteResume(); re.clone(); re.clone(); re.clone(); re.clone(); } }
-
上面实际上,把new 用代码隐藏了,本质上对象的产生还是靠new产生的,只是耐看了一些上面具备了原型模式的形态,但产生的对象并不能复制对象的当前运行时状态,所以需要做一些改进。
-
使用克隆
-
克隆的得到的是一个新的对象,但是这个新对象的内容是克隆对象的当前运行时内容
-
只有实现了Cloneable这个接口的类才可以被拷贝
-
在克隆对象的过程中,没有调用构造函数。因为Object类的clone方法原理是从堆内存以二进制流的方式进行拷贝,重新分配一个内存块,将当前内存状态拷贝到新开辟的的内存,并将堆中开辟的新内存地址返回给栈中的对象引用。
-
克隆分为深克隆和浅克隆,只要区别在于是否支持对象引用类型的成员变量的复制。结合下面简历例子,调用对象clone方法这里是浅拷贝。
public class Test { public static void main(String[] args) throws CloneNotSupportedException { Resume re = new Resume(); re.setAge(10); re.setName("x1同学"); re.setHobby(new String[]{"吃饭","睡觉","打豆豆"}); System.out.println(re); re.setAge(11); Resume re1 = (Resume) re.clone(); String [] hobbies = re1.getHobby(); hobbies[0]="打游戏"; re1.setHobby(hobbies); System.out.println(re1); System.out.println(re); } }
-
运行结果
Resume{name='x1同学', age=10, hobby=[吃饭, 睡觉, 打豆豆]} Resume{name='x1同学', age=11, hobby=[打游戏, 睡觉, 打豆豆]} Resume{name='x1同学', age=11, hobby=[打游戏, 睡觉, 打豆豆]}
-
举例
-
Reume
package com.prototype; import java.util.Arrays; public class Resume implements Cloneable{ // public Resume clone(); private String name; private Integer age; private String[] hobby; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String[] getHobby() { return hobby; } public void setHobby(String[] hobby) { this.hobby = hobby; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Resume{" + "name='" + name + '\'' + ", age=" + age + ", hobby=" + Arrays.toString(hobby) + '}'; } }
-
Test
package com.prototype; public class Test { public static void main(String[] args) throws CloneNotSupportedException { Resume re = new Resume(); re.setAge(10); System.out.println(re); re.setAge(11); Resume re1 = (Resume) re.clone(); System.out.println(re1); } }
-
结果
Resume{name='null', age=10, hobby=null} Resume{name='null', age=11, hobby=null}
-
由上面结果可知,克隆产生新的对象,新对象的内容是克隆对象的当前运行时状态。
-
==用在基本数据类型,比较的是值,用来引用独享,比较的是对象的地址。
-
-
深拷贝:深拷贝在对象拷贝(克隆)时,连同引用类型也拷贝一份。修改Reume中clone方法即可。
@Override protected Object clone() throws CloneNotSupportedException { Resume re = (Resume) super.clone(); String [] hobbies = re.getHobby().clone(); re.setHobby(hobbies); return re; }
-
运行结果
Resume{name='x1同学', age=10, hobby=[吃饭, 睡觉, 打豆豆]} Resume{name='x1同学', age=11, hobby=[打游戏, 睡觉, 打豆豆]} Resume{name='x1同学', age=11, hobby=[吃饭, 睡觉, 打豆豆]}
-
clone比new效率高,只有构造函数特别复杂是,clone优势才会显示出来。
-
-
-