设计模式-行为型模式讲解三(观察者状态中介者)

Posted 小毕超

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-行为型模式讲解三(观察者状态中介者)相关的知识,希望对你有一定的参考价值。

一、行为型设计模式

上篇,我们呢讲解了-行为型设计模式的模板、策略、解释器模式。

文章地址:https://blog.csdn.net/qq_43692950/article/details/120405226

这篇文章我们来讲解下行为型设计模式的观察者、状态、中介者模式。

二、观察者模式

当一个对象被修改时,则会自动通知依赖它的对象。对象间存在一对多关系时就可以选用这个设计模式,优点是观察者和被观察者是抽象耦合的。

举个例子:比如我们在做通知类型的业务时,可能需要同时发送短信和邮件,如果说在需要发送的时候,我们就每个都调用一次发送的方法,就显得代码有些冗余了,采用观察者设计模式则可以有效解决此类问题。

下面使用程序演示下上面的例子:

  1. 定义事件监听的接口
public interface MsgListener<T> {
    void msgEvent(T msg);
}
  1. 定义事件bean对象
@Data
@AllArgsConstructor
public class MyMsgEvent {
    private int code;
    private String msg;
}
  1. 定义邮件的监听实现
@Slf4j
@Component
public class MyMailLinstener implements MsgListener<MyMsgEvent> {
    @Override
    public void msgEvent(MyMsgEvent msg) {
        System.out.println("邮件监听触发" + msg.toString());
    }
}
  1. 定义短信的监听实现
@Slf4j
@Component
public class MySMSListenter implements MsgListener<MyMsgEvent> {
    @Override
    public void msgEvent(MyMsgEvent msg) {
        System.out.println("短信监听触发" + msg.toString());
    }
}
  1. 定义消息发布类
@Slf4j
@Component
public class MsgPublic {
    private static List<MsgListener> list = new ArrayList<>();

    static  {
        list.add(new MyMailLinstener());
        list.add(new MySMSListenter());
    }

    public static void publicMsg(Object o) {
        list.forEach(listener -> listener.msgEvent(o));
    }
}

  1. 演示
public class demo {
    public static void main(String[] args) {
        MyMsgEvent event = new MyMsgEvent(200, "success");
        MsgPublic.publicMsg(event);
    }
}


扩展:
上面的在消息发布类中时写死的目前有哪些实现,如果不写死可以使用Spring来获取MsgListener下的所有子类来发送信息:

@Slf4j
@Component
public class MsgPublic implements ApplicationRunner, ApplicationContextAware {
    private static ApplicationContext applicationContext;
    private List<MsgListener> list = new ArrayList<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(this.applicationContext == null) {
            this.applicationContext = applicationContext;
        }
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Map<String, MsgListener> beanOfType = applicationContext.getBeansOfType(MsgListener.class);
        beanOfType.forEach((key,val) -> {
            list.add(val);
        });
        log.info("注册监听数:"+beanOfType.size());
    }

    public void publicMsg(Object o) {
        list.forEach(listener -> {
            listener.msgEvent(o);
        });
    }
    
}

另外,在Spring中,就有这种封装ApplicationListener来便于我们使用,下面看下Spring的使用:

  1. 定义消息bean
public class MsgInfo extends ApplicationEvent {
    private int code;
    private String msg;

    public MsgInfo(Object source) {
        super(source);
    }

    public MsgInfo(Object source, int code, String msg) {
        super(source);
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "MsgInfo{" +
                "code=" + code +
                ", msg='" + msg + '\\'' +
                '}';
    }
}
  1. 定义短信监听
@Slf4j
@Component
public class SMSListener implements ApplicationListener<MsgInfo> {

    @Override
    public void onApplicationEvent(MsgInfo msgInfo) {
        log.info("短信监听触发" + msgInfo.toString());
    }
}
  1. 定义邮件监听
@Slf4j
@Component
public class EmailListener implements ApplicationListener<MsgInfo> {
    @Override
    public void onApplicationEvent(MsgInfo msgInfo) {
        log.info("邮件监听触发" + msgInfo.toString());
    }
}
  1. 演示
@RestController
public class SendTest {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @GetMapping("/TestPublish")
    public String testPublish() {
        applicationEventPublisher.publishEvent(new MsgInfo(this, 200, "abc"));
        return "success";
    }
}

三、状态模式

在状态模式(State Pattern)中,类的行为是基于它的状态改变的。我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。

举个例子,在用户登录状态方面,有登录状态,登出状态等,在登录和登出时,我们不仅要改变状态还要做一些附加的操作,那如果我们修改状态时,就能自动触发附加操作,那岂不是代码的维护性更高了,采用状态模式就可以解决这类问题。

下面使用程序演示下上面的例子:

  1. 定义状态接口
public interface StateInterFace {
    void login(Context context);
}
  1. 定义登录状态的实现
public class LoginStatus implements StateInterFace {
    @Override
    public void login(Context context) {
        System.out.println("登录的附加操作!");
        System.out.println("已经切换到登陆状态");
    }
}
  1. 定义登出状态的实现
public class LoginOutStatus implements StateInterFace {
    @Override
    public void login(Context context) {
        System.out.println("登出附加操作!");
        System.out.println("已切换到登出状态!");
    }
}
  1. 定义Context
public class Context {
    public static final StateInterFace LOGIN_STATUS = new LoginStatus();
    public static final StateInterFace LOGINOUT_STATUS = new LoginOutStatus();
    public static final StateInterFace DEFAULT_STATUS = LOGIN_STATUS;


    public void setState(StateInterFace state) {
        state.login(this);
    }
}
  1. 演示
public class demo {
    public static void main(String[] args) {
        Context context = new Context();
        context.setState(Context.LOGIN_STATUS);
        context.setState(Context.LOGINOUT_STATUS);
    }
}

四、中介者模式

中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。它的优点为降低了类的复杂度,将一对多转化成了一对一,各个类之间的解耦,符合迪米特原则。

举个例子:比如我们发送消息,我们肯定要调用发送消息的封装,肯定需要传递消息内容和消息的接收人信息这两个参数吧,但问题来了,我要发给小明要把消息接收人指定为小明的人员信息,要发给小红要把消息接收人指定为小红的人员信息。现在我们就像既然我都拿到接受人的信息了,为什么不能直接给他发送呢,反而多了一步调用发消息的封装。采用中介者模式的思想,我们可以在每个人员信息的类中去调用发消息的封装,就省去了我们多的哪一步,此时中介者就是人员信息类。

下面使用程序演示下上面的例子:

  1. 定义发送消息的类
public class ChatRoom {
    public static void showMessage(User user, String message) {
        System.out.println("发送信息:" + message + ", 接收人:" + user);
    }
}
  1. 定义人员信息类
@Data
@AllArgsConstructor
public class User {
   private String name;
 
   public void sendMessage(String message){
      ChatRoom.showMessage(this,message);
   }
}
  1. 演示
public class demo {
   public static void main(String[] args) {
      User robert = new User("小明");
      User john = new User("小红");
 
      robert.sendMessage("哈哈哈");
      john.sendMessage("嗯嗯");
   }
}

以上是关于设计模式-行为型模式讲解三(观察者状态中介者)的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之行为型模式

php设计模式:行为型模式

设计模式-行为型

23种状态模式的理解

设计模式之行为型中介模式

23种设计模式归纳总结——行为型