設計模式(Java隨筆)—原型模式
阿新 • • 發佈:2018-12-14
原型模式(Prototype Pattern):誒呀,一種灰常簡單的模式,就是要求物件實現一個可以“克隆”自身的介面,這樣就可以通過複製一個例項物件本身來建立一個新的例項。只要實現了克隆自身的方法,就可以通過這個方法來獲取新的物件,而無須再去通過new來建立。
Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.
用原型例項指定建立物件的種類,並且通過複製這些原型建立新的物件。
角色:
- 客戶(Client):提出建立物件的請求
- 抽象原型(Prototype):給出所有具體原型所需要的藉口(如:抽象一個克隆方法)
- 具體原型(Concrete Prototype):被複制的物件,必須實現抽象原型介面
Java中內建了克隆機制,Object類有一個clone()方法,能夠實現物件的克隆,因此在java中實現一個類支援克隆只需兩步:
- 實現Cloneable介面
- 覆蓋Object的clone()方法,完成物件的克隆操作,由於該clone()方法的訪問性是protected的,為了使外部可以呼叫,可以在覆蓋的時候將其改為public
注意:(由於clone()方法是protected修飾的,因此需要實現Cloneable接口才能呼叫,同時需要覆寫clone()方法才能呼叫。)
列子:群發簡訊,對簡訊類物件可以採用克隆的方式,原型模式是在記憶體二進位制流的複製,要比new一個物件效能好。
import java.util.ArrayList; import java.util.List; public class PrototypeModel { /** * 原型模式 */ //main方法充當客戶類 public static void main(String[] args) { //裝載使用者資料(實際開發中應該從資料庫中獲取使用者資訊) List<User> userList=new ArrayList<User>(); User user=new User(); User user1; user1=(User) user.clone(); user1.setName("張三"); user1.setPhone("15678948737"); userList.add(user1); user1=(User) user.clone(); user1.setName("小明"); user1.setPhone("15698645674"); userList.add(user1); //呼叫傳送簡訊 Message mes=new Message("元旦快樂"); sendMessage(userList, mes); } //傳送簡訊 public static void sendMessage(List<User> list,Message mes){ Message message; for(User user: list){ //呼叫訊息物件的克隆方法 message=(Message) mes.clone(); message.setPhone(user.getPhone()); message.setReceiver(user.getName()); System.out.println("資訊傳送成功...收件人:"+message.getPhone()+" ||"+message.toString()); } } } //抽象原型(抽象克隆方法) interface MesClone extends Cloneable{ public MesClone clone(); } //具體原型(簡訊類) class Message implements MesClone{ private String receiver;//接收者 private String phone;//接收人電話號碼 private String text;//傳送資訊內容 public Message(String text){ this.text=text; } public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this.receiver = receiver; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } //實現克隆方法 public MesClone clone(){ try { return (MesClone)super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } } //使用者資訊封裝類 class User implements Cloneable{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } private String phone; //克隆方法 public Object clone(){ try { return (User)super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } }
java中Object提供的clone()方法是“淺”克隆,即只複製關聯物件的引用,而不復制關聯物件的資料。如果需要“深”克隆,則需要在覆蓋clone()方法時手動控制克隆的深度。
淺拷貝:建立一個新物件,然後將當前物件的非靜態欄位複製到該物件,如果欄位型別是值型別(基本型別)的,那麼對該欄位進行復制;如果欄位是引用型別的,則只複製該欄位的引用而不復制引用指向的物件。此時新物件裡面的引用型別欄位相當於是原始物件裡面引用型別欄位的一個副本,原始物件與新物件裡面的引用欄位指向的是同一個物件。
深拷貝:即將引用型別的屬性內容也拷貝一份新的。利用clone方式進行深拷貝就是將引用型別的類也實現Cloneable,然後對具體原型類的clone方法進行調整。