# 设计模式(Java语言实现) **Repository Path**: wang-zehan2003/java-design-patterns ## Basic Information - **Project Name**: 设计模式(Java语言实现) - **Description**: 使用Java语言实现的设计模式示例,包含笔记和代码 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-04-09 - **Last Updated**: 2024-05-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 观察者模式 ## 概念 >观察者模式(别名:依赖,发布-订阅) >定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并被自动更新 > >Observer Pattern >Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. ## 角色 - **主题(Subject)**:主题是一个接口,该接口规定了具体主题需要实现的方法。 - **观察者(Observer)**:观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。 - **具体主题(ConcreteSubject)**:具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需要使用一个集合,例如ArrayList来存放观察者的引用,以便数据变化时通知具体观察者。 - **具体观察者(ConcreteObserver)**:具体观察者时实现观察者接口类的一个实例。 ## 观察者模式的UML类图 ![观察者模式的UML类图](https://img-blog.csdnimg.cn/direct/8e104aa8caa24576a36619d199a2960a.png#pic_center) ## 观察者模式代码示例 详见Gitee仓库Java设计模式的[Observer包](https://gitee.com/wang-zehan2003/java-design-patterns/tree/master/src/designpatterns/observer) ## update()方法是如何实现的? 在求职中心的问题中,在Observer接口里,定义`hearTelephone()`方法,然后要求具体的观察者对象实现`hearTelephone()`方法来更新数据 `public void hearTelephone(String heardMess);` ## notifyObserver()方法是如何传递的? 具体的主题里有一个列表,用来保存所有的观察者对象 `personList: ArrayList` 每当具体主题的信息发生变化时,会遍历观察者列表,通知每一个观察者。 ```java public void notifyObserver() { if (changed) { for (int i = 0; i < personList.size(); i ++) { Observer observer = personList.get(i); observer.hearTelephone(mess); } changed = false; } } ``` ## 推数据和拉数据 `update()`方法带参数,通过参数来传递数据,这样的方法叫**推数据**。 例如书上的求职中心例子中,通过`hearTelephone(String heardMess)`来传递数据 同时,用`update()`方法来传递数据的话,具体观察者对象中,就不用具体主题对象的引用。 **拉数据**提供获取这些数据的方法,具体观察者得到通知后,可以调用具体主题的方法得到数据,但需要自己判断数据是否发生了变化 ![拉数据UML时序图](https://img-blog.csdnimg.cn/direct/3f01d8e7a6664ad4b737a9c5d7675e98.png#pic_center) ### 拉数据相较于推数据的区别 1. `update()`方法无参数 2. 在主题对象里,定义`getState()`和`setState()`方法供观察者调 3. 需要保存主题对象的引用 ## 观察者模式的优点 1. 具体主题和具体观察者是松耦合关系:具体主题里的观察者列表里保存的是抽象的观察者接口,而不是具体的观察者。 2. 满足开闭原则:对扩展开放,对修改关闭。具体观察者对象增加一个具体主题后,已经存在的主题和观察者都不会修改。 # 策略模式 ## 概念 >**策略模式** >定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于它的客户而变化。 >**Strategy Pattern** >Define a family of algorithms, encapsulate each one, and make them inter changeable. Strategy lets the algorithm vary independently from clients that use it. >引用自*Design Pattern* 这里的客户,是指使用算法的应用程序/调用方。 ## 角色 - **策略(Strategy)**:策略是一个接口,该接口定义若干个算法标识,即定义个若干个抽象方法。 - **具体策略(Concrete Strategy)**:集体策略是实现策略接口的类,具体策略实现策略接口所定义的抽象方法,即给出算法标识的具体算法。 - **上下文(Context)**:上下文是依赖于策略接口的类,即上下文包含有策略声明的变量。 ## 策略模式的UML类图 ![策略模式的UML类图](https://img-blog.csdnimg.cn/direct/d52a79e866d74b8f902aeba0310c2a7c.jpeg#pic_center) ## 代码示例 详见Gitee仓库代码[Strategy包](https://gitee.com/wang-zehan2003/java-design-patterns/tree/master/src/designpatterns/stragetypattern) ## 上下文的作用是什么?能否不用上下文这个角色? 作用:实现策略对象的共享 如果不使用上下文这个角色的话,在其他应用程序里还需要创建新的具体策略的实例。而使用了上下文角色后,具体策略的实例创建过一次后就保存在上下文的策略成员的引用里了,在其他应用程序里再使用该策略时,直接调用上下文的方法即可。 未使用上下文的代码: ```java String[] data = new String[]{"Jack", "Maya", "Mikes", "Shadow"}; TableExporter tb; tb = new HtmlExporter(); System.out.println(tb.getExported(data)); tb = new LineExporter(); System.out.println(tb.getExported(data)); ``` 使用了上下文的代码: ```java String[] data = new String[]{"Jack", "Maya", "Mikes", "Shadow"}; TableExporter tb = new HtmlExporter(); Exporter e = new Exporter(); Exporter.setStrategy(HtmlExporter); System.out.println(e.getExported(data)); ``` ## 策略模式的优点 **松耦合**:上下文和具体策略是松耦合的关系。上下文只知道某一个实现策略接口的实例,而不需要知道具体是哪个类 满足**开闭原则**:当增加新的具体策略时,不需要修改上下文类的代码。