6.观察者模式
(1).概述
定义:
又被称为发布-订阅模式,它定义了一种一对多
的依赖关系,让多个观察者对象同时监听某一个主题对象
。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
(2).结构
在观察者模式中有如下角色:
- Subject:
抽象主题(抽象被观察者)
,抽象主题角色把所有观察者对象保存一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口
,可以增加和删除观察者对象。 - ConcreateSubject::
具体主题
(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。 - Observer:
抽象观察者
,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知更新自己。 - ConcrereObserver:
具体观察者
,实现抽象观察者定义的更新接口,以便在得到主题更改通知更新自身的状态。
(3).实列实现
eg: 微信公众号
在使用微信公众号时,大家都会有这样的体验。当你关注的公众号中新内容更新的话,它就会推送给关注公众号的微信客户端。我们使用观察者模式来模拟这样的场景,微信用户就是观察者
,微信公众号时被观察者
。
抽象主题
package com.jsxs.behavioralModel.observe; /** * @Author Jsxs * @Date 2023/4/23 19:34 * @PackageName:com.jsxs.behavioralModel.observe * @ClassName: Subject * @Description: TODO 抽象主题角色类 * @Version 1.0 */ public interface Subject { // 添加订阅者/观察者对象 void add(Observer observer); // 删除订阅者 void detach(Observer observer); // 通知订阅者更新信息 void notify(String messsage); }
抽象观察者类
package com.jsxs.behavioralModel.observe; /** * @Author Jsxs * @Date 2023/4/23 19:35 * @PackageName:com.jsxs.behavioralModel.observe * @ClassName: Observer * @Description: TODO 抽象观察者类 * @Version 1.0 */ public interface Observer { // 公众号推送的内容 void update(String message); }
具体被观察者
package com.jsxs.behavioralModel.observe; import java.util.ArrayList; import java.util.List; /** * @Author Jsxs * @Date 2023/4/23 19:37 * @PackageName:com.jsxs.behavioralModel.observe * @ClassName: SubscriptionSubject * @Description: TODO 具体主题角色类 * @Version 1.0 */ public class SubscriptionSubject implements Subject{ // 定义以恶搞集合,用来存储多个观察者对象 private List<Observer> weiXinUserList=new ArrayList<>(); @Override public void add(Observer observer) { weiXinUserList.add(observer); } @Override public void detach(Observer observer) { weiXinUserList.remove(observer); } @Override public void notify(String messsage) { // 遍历集合 for (Observer observer : weiXinUserList) { // 调用观察者对象中的update方法 observer.update(messsage); } } }
具体观察者类
package com.jsxs.behavioralModel.observe; /** * @Author Jsxs * @Date 2023/4/23 19:44 * @PackageName:com.jsxs.behavioralModel.observe * @ClassName: WeiXinUser * @Description: TODO 具体观察者角色类 * @Version 1.0 */ public class WeiXinUser implements Observer{ private String name; public WeiXinUser(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name+" 接收到了 "+message); } }
测试
package com.jsxs.behavioralModel.observe; /** * @Author Jsxs * @Date 2023/4/23 19:48 * @PackageName:com.jsxs.behavioralModel.observe * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { // 创建公众号对象 SubscriptionSubject subscriptionSubject = new SubscriptionSubject(); // 订阅公众号 subscriptionSubject.add(new WeiXinUser("孙维看")); subscriptionSubject.add(new WeiXinUser("JSXS")); subscriptionSubject.add(new WeiXinUser("CKQN")); //3.公众号更新文章(发布) subscriptionSubject.notify("你好啊,俺是微信呀"); } }
(4).使用场景
优点:
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
- 被观察者发送通知,所有驻车的观察者都会收到信息【发布-订阅】
缺点:
- 如果观察者非常多的话,那么所有的观察者受到的被观察者发送的通知会耗时。
- 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃
使用场景:
- 对象间存在一对多的关系,一个对象的状态发生改变会影响其他的对象。
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时。
(5).JDK中提供的实现
在Java中,通过java.util.Observable
和 java.ytil.Observer
接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实列。
7.中介者模式
(1).概述
一般来说,同事之间的关系是比较复杂的,多个同事类之间相互关联时,它们之间的关系会呈现复杂的网状结构,这是一种过渡耦合架构.即不利于类的复用,也不稳定
。列如在图中,有6个对象同事,假如对象1发生变化,那么将会有4个对象发生变化。如果对象2发生变化,那么将会有5个对象发生变化,也就是说: 同事类之间直接关联的设计是不好的
。
如果引入中介者模式
的话,那么同事类之间的关系将变为星型关系,任何一个类的变化只能够影响到本类以及中介者类,这样就降低了系统的耦合
。一个好的设计,必定不会把所有的对象关系处理逻辑分装在本类中,而是使用一个专门的类来管理那些不属于自己的行为。
代理对旧功能的增强、中介直接添加新功能
(2).结构
中介模式包含以下主要角色:
- 抽象中介者角色: 它是
中介者的接口
,提供了同事对象注册与转发同事对象信息的抽象方法。 - 具体中介者角色:
实现中介者接口
,定义一个List
来管理同时对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。 - 抽象同事类角色(记住中介):
定义同事类的接口
,保存中介者对象
,提供同事对象交互的抽象方法,实现所有相互影响的同时类的公共功能。 - 具体同事类角色(记住中介): 是
抽象同事类的实现者
,当需要与其他同时对象交互时,由中介者对象负责后续的交互。
(3).案列实现
eg : 租房
现在租房基本都是通过房屋中介,房主将房屋托管给房屋中介,而租房者从房屋中介获取房屋信息。房屋中介充当租房者与房屋所有者之间的中介者。
抽象者中介者
package com.jsxs.behavioralModel.mediator; /** * @Author Jsxs * @Date 2023/4/23 21:31 * @PackageName:com.jsxs.behavioralModel.mediator * @ClassName: Mediator * @Description: TODO 抽象中介者 * @Version 1.0 */ public abstract class Mediator { public abstract void constact(String message,Person person); }
抽象同事类
package com.jsxs.behavioralModel.mediator; /** * @Author Jsxs * @Date 2023/4/23 21:33 * @PackageName:com.jsxs.behavioralModel.mediator * @ClassName: Person * @Description: TODO 抽象同事类 * @Version 1.0 */ public abstract class Person { // 同事姓名 protected String name; // 聚合中介 protected Mediator mediator; public Person(String name, Mediator mediator) { this.name = name; this.mediator = mediator; } }
具体同事类
package com.jsxs.behavioralModel.mediator; /** * @Author Jsxs * @Date 2023/4/23 21:34 * @PackageName:com.jsxs.behavioralModel.mediator * @ClassName: Tenant * @Description: TODO 租房者(具体同事类) * @Version 1.0 */ public class Tenant extends Person{ public Tenant(String name, Mediator mediator) { super(name, mediator); } // 和中介沟通的方法 public void constact(String message){ // 因为父类定义变量是保护类型,所以子类能使用 mediator.constact(message,this); } // 获取信息的方法 public void getMessage(String message){ System.out.println("租房者:"+name+" 获取到的信息是:"+message); } }
package com.jsxs.behavioralModel.mediator; /** * @Author Jsxs * @Date 2023/4/23 21:39 * @PackageName:com.jsxs.behavioralModel.mediator * @ClassName: HouseOwner * @Description: TODO 房东(具体同事) * @Version 1.0 */ public class HouseOwner extends Person{ public HouseOwner(String name, Mediator mediator) { super(name, mediator); } // 和中介沟通的方法 public void constact(String message){ // 因为父类定义变量是保护类型,所以子类能使用 mediator.constact(message,this); } // 获取信息的方法 public void getMessage(String message){ System.out.println("房东:"+name+" 获取到的信息是:"+message); } }
中介者模式
package com.jsxs.behavioralModel.mediator; /** * @Author Jsxs * @Date 2023/4/23 21:42 * @PackageName:com.jsxs.behavioralModel.mediator * @ClassName: MediatorStructure * @Description: TODO 具体的中介者角色类 * @Version 1.0 */ public class MediatorStructure extends Mediator{ // 聚合房屋和租房者 private HouseOwner houseOwner; private Tenant tenant; public HouseOwner getHouseOwner() { return houseOwner; } public void setHouseOwner(HouseOwner houseOwner) { this.houseOwner = houseOwner; } public Tenant getTenant() { return tenant; } public void setTenant(Tenant tenant) { this.tenant = tenant; } @Override public void constact(String message, Person person) { if (person==houseOwner){ tenant.getMessage(message); }else { houseOwner.getMessage(message); } } }
测试:
package com.jsxs.behavioralModel.mediator; /** * @Author Jsxs * @Date 2023/4/23 21:46 * @PackageName:com.jsxs.behavioralModel.mediator * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { // 创建中介者 MediatorStructure mediatorStructure = new MediatorStructure(); // 创建租房者对象 Tenant tenant = new Tenant("顾客: JSXS", mediatorStructure); // 创建房主 HouseOwner houseOwner = new HouseOwner("房主: SKQN", mediatorStructure); // 中介者要知道具体欸都房主和租房者 mediatorStructure.setHouseOwner(houseOwner); mediatorStructure.setTenant(tenant); // 交流 tenant.constact("你那里有房子嘛?"); houseOwner.constact("我这里有房子。"); } }
(4).优缺点
优点:
- 松散耦合: 中介者模式通过把多个同事对象那个之间的交互封装加粗样式到中介者对象里面,从而使得同事对象之间松散耦合,基本上可以做到互补依赖。这样依赖,同事对象就可可以独立地变化和复用,而
不再像以前那样"牵移除而动全身了
"。 - 集中控制交互: 多个同事对象地交互,被封装在中介者对象里面几种管理,使得这些交互行为发生变化的时候,只需要修改中介者对象就可以了,当然如果是已经做好的系统,那么就扩展中介者对象,而各个同事类不需要修改。
-一对多关联转换变为一对一的关联: 没有使用中介者模式的时候,同事对象之间的关系是一对多的,引入中介者对象以后,中介者对象和同事对象的关系通常变为双向的一对一
,这会让对象的关系更容易理解和实现。
缺点:
- 当同事类太多时,中介者的职责将会很大,他会
变得复杂而庞大,以至于系统难以维护
。
使用场景:
系统中对象之间存在复杂的引用关系
,系统结构混乱且难以理解。- 当想创建一个运行于
多个类之间的对象
,又不想生成新的子类时。