• GPT带我学-设计模式-10观察者模式


    1 请你介绍一下观察者模式

    观察者模式(Observer Pattern)是一种设计模式,它定义了对象之间的一对多依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会得到通知并自动更新。
    观察者模式可以在以下场景中应用:

    1 当一个对象的改变需要同时同步到其他对象时,例如多个对象之间的数据同步。

    2 当一个对象的改变会引起其他一系列操作,却又不希望耦合过于紧密时,例如消息通知等。

    3 当系统设计需要增加相应行为而又不影响其他对象,例如事件监听器、插件机制等。

    综上所述,观察者模式通常适用于对象之间存在一对多关系,当一个对象的状态发生改变时,需要同时将这种变化通知其他多个对象并进行更新处理的情况。
    下面列举三个更具体的场景:

    1 消息中心:例如一个社交网站的消息中心,多个用户之间可以互相发送消息,当某个用户发送一条消息时,这条消息需要同步到其他相关的用户的消息中心中。这种情况下就可以使用观察者模式来实现消息的订阅和发布。

    2 股票交易:例如一个股票交易系统,多个客户端需要获取股价的变化,当某只股票价格发生变化时,需要同时通知到所有观察者(即客户端),以更新他们的股票价格显示。这种情况下也可以使用观察者模式来实现。

    3 GUI编程:例如一个窗口控件,当一个控件的状态发生改变时,需要及时通知到其他相关的控件更新自身状态或重新绘制自己。这种情况下也可以考虑使用观察者模式来实现。

    这种模型主要由三个角色构成:

    观察者(Observer):接收并处理被观察者发出的通知。通常,观察者需要定义一个更新函数,用以在接收到通知时更新自己的状态。

    被观察者(Subject):当其状态发生改变时,它需要通知所有观察者。通常,被观察者维护一个观察者列表,并定义添加、删除和通知观察者的方法。

    具体观察者(Concrete Observer)和具体被观察者(Concrete Subject):分别实现观察者和被观察者的接口,完成具体的业务逻辑。

    观察者模式的主要优点是可以在不改变被观察者和观察者的情况下,实现两者之间的松耦合关系。当被观察者发生改变时,所有观察者都会得到通知并更新,非常适合处理一对多的关系。

    典型的应用包括:GUI事件模型、订阅发布模型等。

    2 观察者模式有几种类型

    观察者模式一般分为两大类:拉模型和推模型。

    拉模型:观察者将被观察者对象拉入自己进行处理,也就是说,观察者在接收到被观察者的变更通知后,需要主动调用获取所需信息。这种方式的优点是观察者可以根据需要决定是否调用,提高了灵活性。但是,如果被观察者的数据非常复杂,每个观察者需要的数据又不同,那么观察者在拉取数据的时候可能会感到困难。

    推模型:被观察者主动向观察者推送信息,也就是说,被观察者在状态变化后,会把一些参数推送给观察者。这种方式的优点是观察者可以直接获取到更新的数据,实现方式相对简洁;但同时也失去了一些灵活性,因为被观察者已经决定了要推送的数据,观察者无法根据需要选择。

    在真实的系统设计中,这两种模型具有各自的应用场景,可以根据实际需要选择使用

    3 请用java写一个推模型观察者模式的例子

    观察者模式是一种较为常用的设计模式,它定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

    下面的例子展示了一个基本的观察者模式的实现,其中包含一个主题(Subject),两个观察者(Observer)和一个推送新闻的方法。主题变化时,所有的观察者都会接收到通知。

    首先定义一个 Observable 接口,描绘被观察者的基本结构:

    import java.util.ArrayList;
    import java.util.List;
    
    public class NewsAgency {
       private String news;
       private List<Channel> channels = new ArrayList<>();
    
       public void registerChannel(Channel channel) {
           channels.add(channel);
       }
    
       public void unRegisterChannel(Channel channel) {
           channels.remove(channel);
       }
    
       public void setNews(String news) {
           this.news = news;
           for (Channel channel : channels) {
               channel.update(this.news);
           }
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    定义一个 Observer 接口,代表观察者:

    public interface Channel {
       void update(Object o);
    }
    
    • 1
    • 2
    • 3

    最后,创建两个具体的 Observer 实现:

    public class NewsChannel implements Channel {
       private String news;
    
       @Override
       public void update(Object news) {
           this.news = (String) news;
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试代码

    public class Main {
       public static void main(String[] args) {
           // 创建新闻机构
           NewsAgency observable = new NewsAgency();
           // 创建新闻频道
           NewsChannel observer = new NewsChannel();
    
           // 新闻频道订阅新闻机构
           observable.registerChannel(observer);
    
           // 新闻机构发布新闻
           observable.setNews("Hello, Observer Pattern!");
           // 新闻频道接收到新闻更新
           String news = observer.getNews();
           System.out.println(news);
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在以上示例中,一旦 NewsAgency 设置新闻,所有注册的频道都会接收新闻更新。如果你在 NewsAgency 中添加更多的频道,它们也会在新消息可用时收到更新。

    4 请用java观察者模式写一个订阅发布的例子

    当然可以,以下是一个使用Java观察者模式实现的订阅发布示例:

    首先,我们创建一个主题(Subject)接口,该接口包含了添加、删除观察者以及通知观察者的方法。

    public interface Subject {
        void attach(Observer observer);
        void detach(Observer observer);
        void notifyObservers(String message);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    接下来,我们实现该接口并为其添加一个消息列表,记录待发送的消息。

    public class Newsletter implements Subject {
        private List<Observer> observers = new ArrayList<>();
        private List<String> messages = new ArrayList<>();
    
        @Override
        public void attach(Observer observer) {
            observers.add(observer);
        }
    
        @Override
        public void detach(Observer observer) {
            observers.remove(observer);
        }
    
        @Override
        public void notifyObservers(String message) {
            messages.add(message);
            for (Observer observer : observers) {
                observer.update(messages);
            }
            messages.clear();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这个实现中,我们维护了一个观察者列表和一个消息列表。每次调用notifyObservers()方法时,我们将新的消息添加到列表中,然后遍历观察者列表并调用每个观察者的update()方法,将消息列表作为参数传递给观察者。

    最后,我们定义观察者(Observer)接口,并实现一个具体的观察者类,它将收到来自主题的消息。

    public interface Observer {
        void update(List<String> messages);
    }
    
    public class Subscriber implements Observer {
        private String name;
    
        public Subscriber(String name) {
            this.name = name;
        }
    
        @Override
        public void update(List<String> messages) {
            System.out.printf("%s received %d messages.\n", name, messages.size());
            for (String message : messages) {
                System.out.printf("%s received message: %s\n", name, message);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在该实现中,我们实现了Observer接口并重写了update()方法,该方法将打印出我们接收到的所有消息。然后我们实现了一个具体的观察者类Subscriber,它包含一个名称字段,在构造函数中初始化该字段。

    现在,我们可以测试我们的代码,创建一些订阅者并向他们发送一些消息:

    public static void main(String[] args) {
        Newsletter newsletter = new Newsletter();
        Observer subscriber1 = new Subscriber("John");
        Observer subscriber2 = new Subscriber("Marry");
    
        newsletter.attach(subscriber1);
        newsletter.attach(subscriber2);
    
        newsletter.notifyObservers("Hello, subscribers!");
        newsletter.notifyObservers("How are you today?");
    
        newsletter.detach(subscriber1);
    
        newsletter.notifyObservers("Goodbye, subscribers!");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这个示例中,我们创建了一个Newsletter对象作为主题,并创建了两个Subscriber对象作为观察者。我们将这两个观察者添加到主题中,并向他们发送一些消息。然后,我们从主题中删除第一个观察者,并再次向另一个观察者发送一条消息。

    总之,这个示例演示了如何使用Java观察者模式创建一个基本的订阅发布系统。我们创建一个主题对象来管理所有的观察者,并允许观察者订阅或取消订阅主题的消息,同时也能够将消息广播给所有的观察者。

  • 相关阅读:
    孙帅Spring源码
    说说商标注册
    MTK LCM调试总结
    html静态商城网页制作 基于HTML+CSS+JavaScript在线服装商城店铺商城设计毕业论文源码
    毕业设计:基于STM32采用RFID技术的管理系统(生猪养殖)
    path环境变量设置
    忧虑随日落一起消失&做事的三重门
    科技与教育的盛宴——探讨监控易在82届教装展的新机遇
    Ceph相关部署应用(博客)
    5.2 EF Core性能优化
  • 原文地址:https://blog.csdn.net/qq_37398465/article/details/133932205