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结尾的类通常是装饰器模式

扫描二维码关注公众号,回复: 8873489 查看本文章

观察者模式

我们还是以案例为例:
首先来一个事件类:

@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();
        }

    }
发布了47 篇原创文章 · 获赞 5 · 访问量 1880

猜你喜欢

转载自blog.csdn.net/qq_34361283/article/details/103233724