创建型设计模式 -- 原型模式
一、小案例分析
1、功能需求:
现有一个员工,姓名为Rick,年龄22,ID为193211,如何创建10个完全相同的对象。
2、小菜鸡的答案:
(1)直接new 10个对象就完了。
(2)代码实现:
package prototype.pattern; public class Demo { public static void main(String[] args) { Employee employee = new Employee("Tom", 22, 193211); Employee employee1 = new Employee("Tom", 22, 193211); Employee employee2 = new Employee("Tom", 22, 193211); Employee employee3 = new Employee("Tom", 22, 193211); Employee employee4 = new Employee("Tom", 22, 193211); Employee employee5 = new Employee("Tom", 22, 193211); Employee employee6 = new Employee("Tom", 22, 193211); Employee employee7 = new Employee("Tom", 22, 193211); Employee employee8 = new Employee("Tom", 22, 193211); Employee employee9 = new Employee("Tom", 22, 193211); System.out.println(employee); System.out.println(employee1); System.out.println(employee2); System.out.println(employee3); System.out.println(employee4); System.out.println(employee5); System.out.println(employee6); System.out.println(employee7); System.out.println(employee8); System.out.println(employee9); } } class Employee { private String name; private int age; private long ID; public Employee(String name, int age, long ID) { super(); this.name = name; this.age = age; this.ID = ID; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public long getID() { return ID; } public void setID(long iD) { ID = iD; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + ", ID=" + ID + "]"; } }
(3)代码分析:
容易理解,好操作。但是每次都是初始化对象,而不是动态获得对象,不够灵活,效率低。
二、原型模式
1、什么是原型模式
指的是用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。是一种创建模式,允许一个对象去创建另一个可定制的对象且不用知道如何创建的细节。
2、如何实现(影分身之术)
将一个原型对象传给 发动创建的对象,此对象通过请求原型对象拷贝自身来进行创建,即调用clone方法。
3、clone方法、浅拷贝、深拷贝
可以参照如下地址:
https://www.cnblogs.com/l-y-h/p/10906499.html#_label1
注:
上面链接中只讲述了通过clone方法实现深拷贝(所有涉及到的类均要实现Cloneable接口)。
也可以使用序列化的方式实现深拷贝(推荐,所有涉及到的类均要实现Serializable接口)。
package prototype.pattern; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class Demo { public static void main(String[] args) { Employee employee = new Employee("Tom", 22, 193211); Employee employee2 = (Employee) employee.deepClone(); System.out.println(employee); System.out.println(employee2); } } // 此处若不实现Serializable 接口,会抛出java.lang.NullPointerException异常。 class Person implements Serializable { private String name; private int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } } class Employee implements Serializable { private String name; private int age; private long ID; private Person people = new Person("Jarry", 20); public Employee(String name, int age, long ID) { super(); this.name = name; this.age = age; this.ID = ID; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public long getID() { return ID; } public void setID(long iD) { ID = iD; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + ", ID=" + ID + "]"; } /** * 使用序列化的方式实现深拷贝 * * @return */ public Object deepClone() { ByteArrayOutputStream baos = null; ObjectOutputStream oos = null; ByteArrayInputStream bias = null; ObjectInputStream ois = null; try { // 序列化 baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(this); // 将当前对象以对象流的方式输出 // 反序列化 bias = new ByteArrayInputStream(baos.toByteArray()); ois = new ObjectInputStream(bias); Employee employee = (Employee) ois.readObject(); return employee; } catch (Exception e) { System.out.println(e.getMessage()); return null; } finally { try { baos.close(); oos.close(); bias.close(); ois.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } } }
4、使用原型模式实现上例
(1)使原型类实现 Cloneable 接口(只有实现该接口,才能重写clone方法)。
(2)调用原型对象自身的clone方法实现拷贝。
(3)代码实现:
package prototype.pattern; public class Demo { public static void main(String[] args) { Employee employee = new Employee("Tom", 22, 193211); Employee employee1 = (Employee) employee.clone(); Employee employee2 = (Employee) employee.clone(); Employee employee3 = (Employee) employee.clone(); Employee employee4 = (Employee) employee.clone(); Employee employee5 = (Employee) employee.clone(); Employee employee6 = (Employee) employee.clone(); Employee employee7 = (Employee) employee.clone(); Employee employee8 = (Employee) employee.clone(); Employee employee9 = (Employee) employee.clone(); System.out.println(employee); System.out.println(employee1); System.out.println(employee2); System.out.println(employee3); System.out.println(employee4); System.out.println(employee5); System.out.println(employee6); System.out.println(employee7); System.out.println(employee8); System.out.println(employee9); } } class Employee implements Cloneable { private String name; private int age; private long ID; public Employee(String name, int age, long ID) { super(); this.name = name; this.age = age; this.ID = ID; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public long getID() { return ID; } public void setID(long iD) { ID = iD; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + ", ID=" + ID + "]"; } @Override protected Object clone() { Employee employee = null; try { employee = (Employee) super.clone(); } catch (CloneNotSupportedException e) { System.out.println(e.getMessage()); } return employee; } }
(3)代码分析:
让程序有更好的扩展性与效率,当修改某个原型对象时,其余clone后的对象均会被修改。
(4)UML图:
5、使用原型模式的优缺点
(1)优点:当创建新的对象比较复杂时,使用原型模式可以简化创建流程、且提高创建的效率。不需要重新new对象,而是动态的获取运行中的对象。
(2)缺点:当实现深拷贝的clone方法时,需要给所有涉及到的类加个clone方法,可能会违反开闭原则。
三、Spring中原型模式分析
1、bean的创建
在创建bean的时候,可以选择是单例模式(同一对象) 还是原型模式(不同对象)。