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

举报
程序员-上善若水 发表于 2022/06/23 22:20:18 2022/06/23
【摘要】 一、行为型设计模式 上篇,我们呢讲解了-行为型设计模式的模板、策略、解释器模式。 文章地址:https://blog.csdn.net/qq_43692950/article/details/1...

一、行为型设计模式

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

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

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

二、观察者模式

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

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

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

  1. 定义事件监听的接口
public interface MsgListener<T> {
    void msgEvent(T msg);
}

 
  • 1
  • 2
  • 3
  1. 定义事件bean对象
@Data
@AllArgsConstructor
public class MyMsgEvent {
    private int code;
    private String msg;
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. 定义邮件的监听实现
@Slf4j
@Component
public class MyMailLinstener implements MsgListener<MyMsgEvent> {
    @Override
    public void msgEvent(MyMsgEvent msg) {
        System.out.println("邮件监听触发" + msg.toString());
    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  1. 定义短信的监听实现
@Slf4j
@Component
public class MySMSListenter implements MsgListener<MyMsgEvent> {
    @Override
    public void msgEvent(MyMsgEvent msg) {
        System.out.println("短信监听触发" + msg.toString());
    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  1. 演示
public class demo {
    public static void main(String[] args) {
        MyMsgEvent event = new MyMsgEvent(200, "success");
        MsgPublic.publicMsg(event);
    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述
扩展:
上面的在消息发布类中时写死的目前有哪些实现,如果不写死可以使用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);
        });
    }
    
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

另外,在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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  1. 定义短信监听
@Slf4j
@Component
public class SMSListener implements ApplicationListener<MsgInfo> {

    @Override
    public void onApplicationEvent(MsgInfo msgInfo) {
        log.info("短信监听触发" + msgInfo.toString());
    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. 定义邮件监听
@Slf4j
@Component
public class EmailListener implements ApplicationListener<MsgInfo> {
    @Override
    public void onApplicationEvent(MsgInfo msgInfo) {
        log.info("邮件监听触发" + msgInfo.toString());
    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  1. 演示
@RestController
public class SendTest {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

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

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

三、状态模式

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

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

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

  1. 定义状态接口
public interface StateInterFace {
    void login(Context context);
}

 
  • 1
  • 2
  • 3
  1. 定义登录状态的实现
public class LoginStatus implements StateInterFace {
    @Override
    public void login(Context context) {
        System.out.println("登录的附加操作!");
        System.out.println("已经切换到登陆状态");
    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 定义登出状态的实现
public class LoginOutStatus implements StateInterFace {
    @Override
    public void login(Context context) {
        System.out.println("登出附加操作!");
        System.out.println("已切换到登出状态!");
    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. 演示
public class demo {
    public static void main(String[] args) {
        Context context = new Context();
        context.setState(Context.LOGIN_STATUS);
        context.setState(Context.LOGINOUT_STATUS);
    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

四、中介者模式

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

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

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

  1. 定义发送消息的类
public class ChatRoom {
    public static void showMessage(User user, String message) {
        System.out.println("发送信息:" + message + ", 接收人:" + user);
    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 定义人员信息类
@Data
@AllArgsConstructor
public class User {
   private String name;
 
   public void sendMessage(String message){
      ChatRoom.showMessage(this,message);
   }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. 演示
public class demo {
   public static void main(String[] args) {
      User robert = new User("小明");
      User john = new User("小红");
 
      robert.sendMessage("哈哈哈");
      john.sendMessage("嗯嗯");
   }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

文章来源: blog.csdn.net,作者:小毕超,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/qq_43692950/article/details/120405784

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。