SSM源碼分析之23種設計模式(裝飾器模式和觀察者模式)

23種設計模式之裝飾器模式和觀察者模式

裝飾器模式

爲了某個實現類在不修改原始類的基礎上進行動態地覆蓋或者增加方法
該實現保持跟原有類的層級關係採用裝飾模式
裝飾器模式實際上一種非常特殊的適配器模式

        //雖然 DataInputStream 功能更強大
       //DataInputStream 同樣要實現InputStream
       InputStream in = null;
       FilterInputStream fis = new DataInputStream(in);

上期的適配器模式案例。我們來分析一下:
首先是會員類:

@Data
public class Member {

   private String username;
   private String password;
   private String mid;
   private String info;
}

然後是封裝的返回集

@Data
public class ResultMsg {

   private int code;
   private String msg;
   private Object data;

}

IService接口:

public interface ISigninService {
   public ResultMsg regist(String username, String password);


   /**
    * 登錄的方法
    * @param username
    * @param password
    * @return
    */
   public ResultMsg login(String username, String password);
}

ServiceImpl:

public class SigninService implements ISigninService {

    public ResultMsg regist(String username,String password){
        return  new ResultMsg(200,"註冊成功",new Member());
    }


    /**
     * 登錄的方法
     * @param username
     * @param password
     * @return
     */
    public ResultMsg login(String username,String password){
        return null;
    }
}

好了,我們現在用裝飾器模式來擴展一下新的業務實現:
擴展的接口:

public interface ISigninForThirdService extends ISigninService {


    public ResultMsg loginForQQ(String openId);

    public ResultMsg loginForWechat(String openId);

    public ResultMsg loginForToken(String token);

    public ResultMsg loginForTelphone(String telphone, String code);

    public ResultMsg loginForRegist(String username, String password);


}

擴展的接口實現類:

public class SigninForThirdService implements ISigninForThirdService {

    private ISigninService service;
    public SigninForThirdService(ISigninService service){
        this.service = service;
    }


    public ResultMsg regist(String username, String password) {
        return service.regist(username,password);
    }


    public ResultMsg login(String username, String password) {
        return service.login(username,password);
    }


    public ResultMsg loginForQQ(String openId){
        //1、openId是全局唯一,我們可以把它當做是一個用戶名(加長)
        //2、密碼默認爲QQ_EMPTY
        //3、註冊(在原有系統裏面創建一個用戶)

        //4、調用原來的登錄方法

        return loginForRegist(openId,null);
    }

    public ResultMsg loginForWechat(String openId){
        return null;
    }

    public ResultMsg loginForToken(String token){
        //通過token拿到用戶信息,然後再重新登陸了一次
        return  null;
    }

    public ResultMsg loginForTelphone(String telphone,String code){

        return null;
    }

    public ResultMsg loginForRegist(String username,String password){
        this.regist(username,null);
        return this.login(username,null);
    }

}

我們來測試一下:

    public static void main(String[] args) {

        //原來的功能依舊對外開放,依舊保留
        //新的功能同樣的也可以使用

        ISigninForThirdService signinForThirdService = new SigninForThirdService(new SigninService());

        signinForThirdService.loginForQQ("xxssdsd");

    }

通常spring源碼裏:
以Decorator、Wrapper結尾的類通常是裝飾器模式

觀察者模式

我們還是以案例爲例:
首先來一個事件類:

@Data
public class Event {

    //事件源
    private Object source;
    //通知目標
    private Object target;
    //回調
    private Method callback;
    //觸發
    private String trigger;

    private long time;
}

EventLisenter事件的註冊和監聽:

public class EventLisenter {

    /**
     * /Map相當於是一個註冊器
     */
    protected Map<Enum,Event> events = new HashMap<Enum,Event>();

    public void addLisenter(Enum eventType,Object target,Method callback){
        //註冊事件
        //用反射調用這個方法
        events.put(eventType,new Event(target,callback));
    }

    private void trigger(Event e){
        e.setSource(this);
        e.setTime(System.currentTimeMillis());

        try {
            e.getCallback().invoke(e.getTarget(),e);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }


    protected void trigger(Enum call){
        if(!this.events.containsKey(call)){ return ;}
        trigger(this.events.get(call).setTrigger(call.toString()));
    }


}

然後做一個Subject繼承EventLisenter

public class Subject extends EventLisenter{

    //通常的話,採用動態裏來實現監控,避免了代碼侵入
    public void add(){
        System.out.println("調用添加的方法");
        trigger(SubjectEventType.ON_ADD);
    }

    public void remove(){
        System.out.println("調用刪除的方法");
        trigger(SubjectEventType.ON_RMOVE);
    }

}

定義一下枚舉類:

public enum SubjectEventType {
    ON_ADD,
    ON_RMOVE,
    ON_EDIT,
    ON_QUERY

}

定義Observer:

public class Observer {

    public void advice(Event e){
        System.out.println("=========觸發事件,打印日誌========\n" + e);
    }

}

測試一下:

    public static void main(String[] args) {

        try{

            //觀察者
            Observer observer = new Observer();
            Method advice = Observer.class.getMethod("advice", new Class<?>[]{Event.class});


            //這裏寫Lily
            Subject subject = new Subject();
            subject.addLisenter(SubjectEventType.ON_ADD,observer,advice);
            subject.addLisenter(SubjectEventType.ON_EDIT,observer,advice);
            subject.addLisenter(SubjectEventType.ON_RMOVE,observer,advice);
            subject.addLisenter(SubjectEventType.ON_QUERY,observer,advice);

            subject.add();
            subject.remove();

        }catch (Exception e){
            e.printStackTrace();
        }

    }

再舉個栗子:
被觀察者(如果做過Swing開發的話,有一種似曾相識的感覺)

public class Mouse extends EventLisenter{

    public void click(){
        System.out.println("鼠標單擊");
        this.trigger(MouseEventType.ON_CLICK);
    }


    public void doubleClick(){
        System.out.println("鼠標雙擊");
        this.trigger(MouseEventType.ON_DOUBLE_CLICK);
    }

    public void up(){
        System.out.println("鼠標彈起");
        this.trigger(MouseEventType.ON_UP);
    }

    public void down(){
        System.out.println("鼠標按下");
        this.trigger(MouseEventType.ON_DOWN);
    }


    public void wheel(){
        System.out.println("鼠標滾動");
        this.trigger(MouseEventType.ON_WHEEL);
    }

    public void move(){
        System.out.println("鼠標移動");
        this.trigger(MouseEventType.ON_MOVE);
    }

    public void over(){
        System.out.println("鼠標懸停");
        this.trigger(MouseEventType.ON_OVER);
    }

}

觀察者:

public class MouseEventCallback {

    public void onClick(Event e){
        System.out.println("這是鼠標單擊以後要執行的邏輯");
        System.out.println("=======觸發鼠標單擊事件========\n" + e);
    }

    public void onDoubleClick(Event e){
        System.out.println("=======觸發鼠標雙擊事件========\n" + e);
    }

    public void onUp(Event e){
        System.out.println("=======觸發鼠標彈起事件========\n" + e);
    }
    public void onDown(Event e){
        System.out.println("=======觸發鼠標按下事件========\n" + e);
    }
    public void onMove(Event e){
        System.out.println("=======觸發鼠標移動事件========\n" + e);
    }
    public void onWheel(Event e){
        System.out.println("=======觸發鼠標滾動事件========\n" + e);
    }

    public void onOver(Event e){
        System.out.println("=======觸發鼠標懸停事件========\n" + e);
    }




}

枚舉項:

public enum MouseEventType {
    /**
     * 點擊
     */
    ON_CLICK,
    ON_DOUBLE_CLICK,
    ON_UP,
    ON_DOWN,
    ON_WHEEL,
    ON_MOVE,
    ON_OVER

}

然後我們來測試一下:

public static void main(String[] args) {
        try {

            //人爲的調用鼠標的單擊事件
            Mouse mouse = new Mouse();
            mouse.click();

        }catch (Exception e){
            e.printStackTrace();
        }

    }
發佈了57 篇原創文章 · 獲贊 5 · 訪問量 5029
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章