設計模式:原型模式
定義
原型模式的定義:Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.(用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。)
結構類圖
原型模式的通用類圖:
原型模式非常簡單,它的核心是一個clone方法,通過該方法完成對象的拷貝,在Java中只需要實現Cloneable接口,並且覆蓋Object類的clone方法。
通用源碼
原型模式的通用源碼:
public class PrototypeClass implements Cloneable {
//覆寫父類Object方法
@Override
protected PrototypeClass clone() {
PrototypeClass prototypeClass = null;
try {
prototypeClass = (PrototypeClass) super.clone();
} catch (CloneNotSupportedException e) {
// 異常處理
}
return prototypeClass;
}
}
實現Cloneable接口,然後重寫clone方法,就完成了原型模式!
應用場景舉例
比如客戶提供訂單交給工廠處理。訂單有產品的數量和名稱,公司接受訂單後需要保存最原始的數據作爲存根。公司每個部門在一個訂單內最多隻能生產1000個產品,所以需要將原始訂單進行拆分,然後處理。
抽象訂單類IOrder,定義訂單數量和clone操作:
public interface IOrder extends Cloneable {
int getOrderNumber();
void setOrderNumber(int orderNumber);
IOrder clone();
}
產生兩個訂單實現類,個人訂單類PersonalOrder:
public class PersonalOrder implements IOrder {
private String orderName;
private int orderNumber;
@Override
public int getOrderNumber() {
return orderNumber;
}
@Override
public void setOrderNumber(int orderNumber) {
this.orderNumber = orderNumber;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
@Override
public IOrder clone() {
IOrder order = null;
try {
order = (IOrder) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return order;
}
}
公司訂單類CompanyOrder:
public class CompanyOrder implements IOrder {
private String orderName;
private int orderNumber;
@Override
public int getOrderNumber() {
return orderNumber;
}
@Override
public void setOrderNumber(int orderNumber) {
this.orderNumber = orderNumber;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
@Override
public IOrder clone() {
IOrder order = null;
try {
order = (IOrder) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return order;
}
}
訂單處理類OrderDealFactory,將原始訂單進行拆分處理:
public class OrderDealFactory {
public void dealOrder(IOrder order) {
int number = order.getOrderNumber();
while (number > 0) {
/**
* 如果不使用原型模式,需要根據實際類型new對象,來保存原始數據
if (order instanceof PersonalOrder) {
IOrder iOrder = null;
PersonalOrder personalOrder = (PersonalOrder) order;
PersonalOrder newOrder = new PersonalOrder();
newOrder.setOrderName(personalOrder.getOrderName());
newOrder.setOrderNumber(number >= 1000 ? 1000 : number);
iOrder = personalOrder;
System.out.println("原始訂單: " + iOrder.getOrderNumber());
System.out.println("newOrder number = " + newOrder.getOrderNumber());
number -= 1000;
}
*/
IOrder newOrder = (IOrder) order.clone();
newOrder.setOrderNumber(number >= 1000 ? 1000 : number);
System.out.println("原始訂單: " + order.getOrderNumber());
System.out.println("newOrder number = " + newOrder.getOrderNumber());
number -= 1000;
}
}
}
場景類的調用方法如下:
public class Client {
public static void main(String[] args) {
OrderDealFactory factory = new OrderDealFactory();
PersonalOrder order = new PersonalOrder();
order.setOrderName("個人訂單");
order.setOrderNumber(3200);
factory.dealOrder(order);
}
}
淺拷貝、深拷貝
Object類的clone方法的原理是從內存中(具體地說就是堆內存)以二進制流的方式進行拷貝,重新分配一個內存塊。所以是淺拷貝,拷貝對象內部的引用對象是不會被拷貝的。即:淺拷貝前後的對象,內部的數組和引用對象,指向的還是同一片內存。
總結
- 原型模式是在內存二進制流的拷貝,要比直接new一個對象性能好很多。
- 在上面的例子中,增加一個訂單類,訂單處理類不需要修改,符合開閉原則。