設計模式之觀察和代理

weixin_33912445發表於2018-12-18

1.觀察者模式

其實就是釋出訂閱模式,釋出者釋出資訊,訂閱者獲取資訊,訂閱了就能收到資訊,沒訂閱就收不到資訊。

  • 1.1 抽象被觀察者角色:也就是一個抽象主題,它把所有對觀察者物件的引用儲存在一個集合中,每個主題都可以有任意數量的觀察者。抽象主題提供一個介面,可以增加和刪除觀察者角色。一般用一個抽象類和介面來實現。
  • 1.2 抽象觀察者角色:為所有的具體觀察者定義一個介面,在得到主題通知時更新自己。
  • 1.3 具體被觀察者角色:也就是一個具體的主題,在集體主題的內部狀態改變時,所有登記過的觀察者發出通知。
  • 1.4 具體觀察者角色:實現抽象觀察者角色所需要的更新介面,一邊使本身的狀態與製圖的狀態相協調。
public interface Subject {

    /*增加觀察者*/
    public void add(Observer observer);

    /*刪除觀察者*/
    public void del(Observer observer);

    /*通知所有的觀察者*/
    public void notifyObservers();

    /*自身的操作*/
    public void operation();

}

public abstract class AbstractSubject implements Subject {

    private Vector<Observer> vector = new Vector<>();

    @Override
    public void add(Observer observer) {
        vector.add(observer);
    }

    @Override
    public void del(Observer observer) {
        vector.remove(observer);
    }

    @Override
    public void notifyObservers() {
        Enumeration<Observer> enumeration = vector.elements();
        while (enumeration.hasMoreElements()){
            enumeration.nextElement().update();
        }
    }
}

public interface Observer {
    public void update();
}
public class Observer1 implements Observer {
    @Override
    public void update() {
        System.out.println("observer1 have received!");
    }
}
public class Observer2 implements Observer {
    @Override
    public void update() {
        System.out.println("observer2 has received");
    }
}
public class Test {

    public static void main(String[] args) {
        Subject sub = new MySubject();
        sub.add(new Observer1());
        sub.add(new Observer2());

        sub.operation();
    }
}

2.代理模式

代理模式的定義:代理模式給某一個物件提供一個代理物件,並由代理物件控制對原物件的引用。通俗的來講代理模式就是我們生活中常見的中介。

舉個例子來說明:假如說我現在想買一輛二手車,雖然我可以自己去找車源,做質量檢測等一系列的車輛過戶流程,但是這確實太浪費我得時間和精力了。我只是想買一輛車而已為什麼我還要額外做這麼多事呢?於是我就通過中介公司來買車,他們來給我找車源,幫我辦理車輛過戶流程,我只是負責選擇自己喜歡的車,然後付錢就可以了。

2.1. 分類
  • 靜態代理是建立或特定工具自動生成原始碼,在對其編譯。在程式執行之前,代理類.class檔案就已經被建立了。
  • 動態代理是在程式執行時通過反射機制動態建立的。
2.2. 靜態代理實現
public interface Sourceable {
    public void method();
}
public class Source implements Sourceable {
    @Override
    public void method() {
        System.out.println("the original method!");
    }
}
public class Proxy implements Sourceable {

    private Source source;

    public Proxy() {
        super();
        this.source = new Source();
    }

    @Override
    public void method() {
        before();
        source.method();
        atfer();
    }

    private void atfer() {
        System.out.println("after proxy!");
    }
    private void before() {
        System.out.println("before proxy!");
    }
}

public class Test {

    public static void main(String[] args) {
        Sourceable sourceable = new Proxy();
        sourceable.method();
    }
}

2.3. 動態代理實現(JDK)
public class DynamicProxyHandler implements InvocationHandler {

    private Object object;

    public DynamicProxyHandler(final Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("買房前準備");
        Object result = method.invoke(object, args);
        System.out.println("買房後裝修");
        return result;
    }
}
public class DynamicProxyTest {
    public static void main(String[] args) {
        BuyHouse buyHouse = new BuyHouseImpl();
        BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), new
                Class[]{BuyHouse.class}, new DynamicProxyHandler(buyHouse));
        proxyBuyHouse.buyHosue();
    }
}
2.4. 動態代理實現(CGLIB代理)
public class CglibProxy implements MethodInterceptor {
    private Object target;
    public Object getInstance(final Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("買房前準備");
        Object result = methodProxy.invoke(object, args);
        System.out.println("買房後裝修");
        return result;
    }
}
public class CglibProxyTest {
    public static void main(String[] args){
        BuyHouse buyHouse = new BuyHouseImpl();
        CglibProxy cglibProxy = new CglibProxy();
        BuyHouseImpl buyHouseCglibProxy = (BuyHouseImpl) cglibProxy.getInstance(buyHouse);
        buyHouseCglibProxy.buyHosue();
    }
}

總結:CGLIB建立的動態代理物件比JDK建立的動態代理物件的效能更高,但是CGLIB建立代理物件時所花費的時間卻比JDK多得多。所以對於單例的物件,因為無需頻繁建立物件,用CGLIB合適,反之使用JDK方式要更為合適一些。同時由於CGLib由於是採用動態建立子類的方法,對於final修飾的方法無法進行代理。

相關文章