有一個產品它有多個觸發事件,它產生的時候觸發一個創建事件,修改的時候觸發修改事件,刪除的時候觸發刪除事件,這就類似於我們的文本框,初始化(也就是創建)的時候要觸發一個onLoad或onCreate事件,修改的時候觸發onChange事件,雙擊(類似於刪除)的時候又觸發onDbClick事件。
主要的設計模式:
- 工廠方法模式:負責產生產品對象,方便產品的修改和擴展,並且實現產品和工廠的緊耦合,避免產品隨意被創建而無觸發事件的情況發生。
- 橋樑模式:在產品和事件兩個對象的關係中使用橋樑模式,這樣兩者都可以自由地擴展而不會破壞原有的封裝。
- 觀察者模式:使用觀察者模式,使事件的變化通知處理者,而且觀察者模式可以有多個觀察者,也就是說這個架構是可以有多層級、多分類的處理者。想重新擴展一個新類型(新接口)的觀察者,只需要擴展ProductEvent即可。
- 中介者模式:使用中介者模式處理事件與事件和處理者與處理者之間的耦合關係。
(1)構建產品和產品工廠
- 產品要有創建、修改、銷燬的動作,使用工廠方法模式。
- 產品也可以通過克隆方式產生,使用原型模式。
- 產品只能由工廠類創建,不能被其他對象通過new方式創建,用單來源調用(Single Call)方法,即一個對象只能由固定的對象初始化。
public class Product implements Cloneable {
private String name; //產品名稱
private boolean canChanged = false; //屬性是否可以變更
public Product(ProductManager manager,String name) {
if (manager.isCreateProduct()) {
canChanged = true;
this.name = name;
}
}
public String getName() {
return name;
}
public void setName(String name) {
if (canChanged) {
this.name = name;
}
}
@Override
public Product clone() {
Product product = null;
try {
product = (Product)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return product;
}
}
import com.sfq.impl.ProductEventType;
public class ProductManager {
private boolean isPermittedCreate = false;
//建立一個產品
public Product createProduct(String name) {
isPermittedCreate = true;
Product product = new Product(this, name);
return product;
}
//廢棄一個產品
public void abandonProduct(Product p) {
p = null; //銷燬掉一個產品,例如刪除數據庫記錄
}
//修改一個產品
public void editProduct(Product p,String name) {
p.setName(name);
}
//獲得是否可以創建一個產品
public boolean isCreateProduct() {
return isPermittedCreate;
}
//克隆一個產品
public Product clone(Product p) {
return p.clone();
}
}
單來源調用(Single Call):在工廠類ProductManager中定義了一個私有變量isCreateProduct,該變量只有在工廠類的createProduct函數中才能設置爲true,在創建產品的時候,產品類Product的構造函數要求傳遞工廠對象,然後判斷是否能夠創建產品。
注意:採用單來源調用的兩個對象一般是組合關係,兩者有相同的生命期,它通常適用於有單例模式和工廠方法模式的場景中。
(2)觸發事件
- 產品新建要觸發事件,還要有人去處理這個事件,使用觀察者模式。
- 觀察者爲EventDispatch類,它使用了單例模式,避免對象膨脹,但同時也帶來了性能及線程安全隱患。
//定義了4個事件類型,分別是新建、修改、刪除以及克隆
public enum ProductEventType {
NEW_PRODUCT(1),
DEL_PRODUCT(2),
EDIT_PRODUCT(3),
CLONE_PRODUCT(4);
private int value = 0;
private ProductEventType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
import java.util.Observable;
import com.sfq.impl.ProductEventType;
public class ProductEvent extends Observable {
private Product source; //事件起源
private ProductEventType type; //事件類型
//傳入事件的源頭,默認爲新建類型
public ProductEvent(Product source) {
this(source,ProductEventType.NEW_PRODUCT);
}
//事件源頭及事件類型
public ProductEvent(Product source, ProductEventType type) {
this.source = source;
this.type = type;
notifyEventDispatch();
}
//獲得事件起源
public Product getSource() {
return source;
}
//獲得事件類型
public ProductEventType getEventType() {
return this.type;
}
//通知事件處理中心
private void notifyEventDispatch() {
super.addObserver(EventDispatch.getEventDispatch());
super.setChanged();
super.notifyObservers(source);
}
}
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;
import com.sfq.impl.EventCustomType;
import com.sfq.impl.EventCustomer;
public class EventDispatch implements Observer {
//單例模式
private final static EventDispatch dispatch = new EventDispatch();
private EventDispatch() { //設置爲私有,不允許生成新的實例
}
//獲得單例對象
public static EventDispatch getEventDispatch() {
return dispatch;
}
//事件觸發
@Override
public void update(Observable o, Object arg) {
}
}
被觀察者ProductEvent的動作發生變化後,會通過notifyEventDispatch()方法通知觀察者EventDispatch,然後觀察者通過 update()方法作出反應,這裏暫時空着,還沒反應。
(3)關聯產品和產品事件
產品和產品事件是兩個獨立的對象,兩者都可以獨立地擴展,使用橋樑模式。這裏使用產品管理類ProductManagger作爲橋樑。
ProductManagger類補充如下:
import com.sfq.impl.ProductEventType;
public class ProductManager {
private boolean isPermittedCreate = false;
//建立一個產品
public Product createProduct(String name) {
isPermittedCreate = true;
Product product = new Product(this, name);
//產生一個創建事件
new ProductEvent(product,ProductEventType.NEW_PRODUCT);
return product;
}
//廢棄一個產品
public void abandonProduct(Product p) {
new ProductEvent(p,ProductEventType.DEL_PRODUCT);
p = null; //銷燬掉一個產品,例如刪除數據庫記錄
}
//修改一個產品
public void editProduct(Product p,String name) {
p.setName(name);
new ProductEvent(p,ProductEventType.EDIT_PRODUCT);
}
//獲得是否可以創建一個產品
public boolean isCreateProduct() {
return isPermittedCreate;
}
//克隆一個產品
public Product clone(Product p) {
new ProductEvent(p,ProductEventType.CLONE_PRODUCT);
return p.clone();
}
}
(4)事件的處理
現在只有1個產品類,如果產品類很多,不可能每個產品事件都寫一個處理者,對於產品事件來說,它最希望的結果就是我通知了事件處理者(也就是觀察者模式的觀察者),其他具體怎麼處理由觀察者來解決,那觀察者怎麼來處理這麼多的事件呢?事件的處理者必然有N多個。即如下圖所示:
我們可以使用中介者模式。把 EventDispatch類作爲事件分發的中介者,事件的處理者都是具體的同事類,它們有着相似的行爲,都是處理產品事件,但是又有不相同的邏輯,每個同事類對事件都有不同的處理行爲。
package com.sfq.action;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;
import com.sfq.impl.EventCustomType;
import com.sfq.impl.EventCustomer;
public class EventDispatch implements Observer {
//單例模式
private final static EventDispatch dispatch = new EventDispatch();
//事件消費者
private Vector<EventCustomer> customer = new Vector<EventCustomer>();
private EventDispatch() { //設置爲私有,不允許生成新的實例
}
//獲得單例對象
public static EventDispatch getEventDispatch() {
return dispatch;
}
//事件觸發
@Override
public void update(Observable o, Object arg) {
//事件的源頭
Product product = (Product)arg;
//事件
ProductEvent event = (ProductEvent)o;
//處理者處理,這裏是中介者模式的核心
for(EventCustomer e:customer) {
//處理能力是否匹配
for(EventCustomType t:e.getCustomType()) {
if (t.getValue() == event.getEventType().getValue()) {
e.exec(event);
}
}
}
}
//註冊事件處理者
public void registerCustomer(EventCustomer _customer) {
this.customer.add(_customer);
}
}
import java.util.Vector;
import com.sfq.action.ProductEvent;
public abstract class EventCustomer {
//容納每個消費者能夠處理的級別
private Vector<EventCustomType> customType = new Vector<EventCustomType>();
//每個消費者都要聲明自己處理哪一類別的事件
public EventCustomer(EventCustomType _type) {
addCustomType(_type);
}
//每個消費者可以消費多個事件
public void addCustomType(EventCustomType _type) {
customType.add(_type);
}
//得到自己的處理能力
public Vector<EventCustomType> getCustomType(){
return customType;
}
//每個事件都要對事件進行聲明式消費
public abstract void exec(ProductEvent event);
}
public enum EventCustomType {
//新建事件
NEW(1),
//刪除事件
DEL(2),
//修改事件
EDIT(3),
//克隆事件
CLONE(4);
private int value = 0;
private EventCustomType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
import com.sfq.impl.EventCustomType;
import com.sfq.impl.EventCustomer;
import com.sfq.impl.ProductEventType;
public class Beggar extends EventCustomer {
public Beggar() {
super(EventCustomType.DEL);
}
@Override
public void exec(ProductEvent event) {
//事件的源頭
Product p = event.getSource();
//事件類型
ProductEventType type = event.getEventType();
System.out.println("乞丐處理事件:" + p.getName() + "銷燬,事件類型=" + type);
}
}
import com.sfq.impl.EventCustomType;
import com.sfq.impl.EventCustomer;
import com.sfq.impl.ProductEventType;
public class Commoner extends EventCustomer {
public Commoner() {
super(EventCustomType.NEW);
}
@Override
public void exec(ProductEvent event) {
//事件的源頭
Product p = event.getSource();
//事件類型
ProductEventType type = event.getEventType();
System.out.println("平民處理事件:" + p.getName() + "誕生記,事件類型=" + type);
}
}
import com.sfq.impl.EventCustomType;
import com.sfq.impl.EventCustomer;
import com.sfq.impl.ProductEventType;
public class Nobleman extends EventCustomer {
public Nobleman() {
super(EventCustomType.EDIT);
super.addCustomType(EventCustomType.CLONE);
}
@Override
public void exec(ProductEvent event) {
//事件的源頭
Product p = event.getSource();
//事件類型
ProductEventType type = event.getEventType();
if (type.getValue() == EventCustomType.CLONE.getValue()) {
System.out.println("貴族處理事件:" + p.getName() + "克隆,事件類型=" + type);
} else {
System.out.println("貴族處理事件:" + p.getName() + "修改,事件類型=" + type);
}
}
}
import com.sfq.action.Beggar;
import com.sfq.action.Commoner;
import com.sfq.action.EventDispatch;
import com.sfq.action.Nobleman;
import com.sfq.action.Product;
import com.sfq.action.ProductManager;
public class Client {
public static void main(String[] args) {
//獲得事件分發中心
EventDispatch dispatch = EventDispatch.getEventDispatch();
//接受乞丐對事件的處理
dispatch.registerCustomer(new Beggar());
//接受平民對事件的處理
dispatch.registerCustomer(new Commoner());
//接受貴族對事件的處理
dispatch.registerCustomer(new Nobleman());
//建立一個原子彈生成工廠
ProductManager factory = new ProductManager();
//製作一個產品
System.out.println("-----模擬創建產品事件-----");
System.out.println("創建一個叫做小男孩的原子彈");
Product p = factory.createProduct("小男孩原子彈");
//修改一個產品
System.out.println("\n-----模擬修改產品事件-----");
System.out.println("把小男孩原子彈修改爲胖子號原子彈");
factory.editProduct(p, "胖子號原子彈");
//再克隆一個原子彈
System.out.println("\n-----模擬克隆產品事件-----");
System.out.println("克隆胖子號原子彈");
factory.clone(p);
//遺棄一個產品
System.out.println("\n-----模擬銷燬產品事件-----");
System.out.println("遺棄胖子號原子彈");
factory.abandonProduct(p);
}
}
結果
-----模擬創建產品事件-----
創建一個叫做小男孩的原子彈
平民處理事件:小男孩原子彈誕生記,事件類型=NEW_PRODUCT
-----模擬修改產品事件-----
把小男孩原子彈修改爲胖子號原子彈
貴族處理事件:胖子號原子彈修改,事件類型=EDIT_PRODUCT
-----模擬克隆產品事件-----
克隆胖子號原子彈
貴族處理事件:胖子號原子彈克隆,事件類型=CLONE_PRODUCT
-----模擬銷燬產品事件-----
遺棄胖子號原子彈
乞丐處理事件:胖子號原子彈銷燬,事件類型=DEL_PRODUCT
如果想繼續擴展:
- 使用責任鏈模式,可以解決一個處理者處理多個事件的問題;
- 使用模板方法模式,可以實現處理者的啓用、停用等;
- 使用裝飾模式,可以實現事件的包裝、處理者功能的強化等。