一、小案例分析 1、功能需求: 現有一個員工,姓名為Rick,年齡22,ID為193211,如何創建10個完全相同的對象。 2、小菜雞的答案: (1)直接new 10個對象就完了。(2)代碼實現: (3)代碼分析: 容易理解,好操作。但是每次都是初始化對象,而不是動態獲得對象,不夠靈活,效率低。 二 ...
一、小案例分析
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的時候,可以選擇是單例模式(同一對象) 還是原型模式(不同對象)。