写点什么

设计模式之禅(二)

作者:青柚1943
  • 2022 年 7 月 24 日
  • 本文字数:2461 字

    阅读完需:约 8 分钟

设计模式之禅(二)

1 面向对象设计

2 设计模式分类

3 常用设计模式

3.1 观察者模式

  • 定义

Define a one-to-many dependency betweeen objects so that when one object changes state,all dependents are notified and updated automatically.

定义对象间一种一对多的依赖关系,使得当一个对象状态发生改变时,则所有依赖它的对象都会得到通知并被更新。

  • 观察者(Observer)观察者接到消息后,进行更新操作,即对接收到的消息进行处理。

  • 被观察者(Subject)定义被观察者必须实现的职责,管理并通知观察者。

  • 优点

  • 观察者和被观察者之间是抽象耦合的(不用被观察者逐个主动调用观察者中的修改方法);

  • 观察者和被观察者之间建立一套触发机制。

  • 实现

  • UML 图

  • 场景

电商 ERP 对接了很多电商平台,各个平台和 ERP 之间的商品、订单等数据是同步的。如果 ERP 修改某个商品的信息,则需要将修改后的商品信息同步到各个平台。

首先,这里是一对多的关系(一个 ERP,对应多个电商平台);其次,电商平台数据依赖 ERP(ERP 数据更新需要同步给各个电商平台)。基于这两点,我们可以采用观察者模式来设计程序(当然真实场景中,我们不会这么去做,我们可以采用消息队列来完成这一工作)。


// 被观察者(ERP),管理并通知观察者(各个平台API)public abstract class SubjectERPAbstract{ //定义一个观察者容器(多个api需要同步商品修改数据) private List<IObserverApiProvider> apiProviders=new List<IObserverApiProvider>(); //增加观察者 public void AddProvider(IObserverApiProvider provider) => this.apiProviders.Add(provider); //删除观察者 public void RemoveProvider(IObserverApiProvider provider) => this.apiProviders.Remove(provider); //通知观察者(观察者做响应处理) public void Notify() { //被观察者和观察者之间是抽象层依赖 foreach(IObserverApiProvider provider in apiProviders) { provider.Update(); } }}
public class SubjectERP : SubjectERPAbstract{ public void UpdateCommodity() { //Do something:Update commodity...
this.Notify();//然后通知所有平台同步商品信息 }}
//观察者抽象层(多个平台API)public interface IObserverApiProvider { //更新商品 void Update();}
public class ApiProvider : IObserverApiProvider{ //根据不同平台做差异化更新
public void Update () { Console.WriteLine("API同步商品数据"); }}
public class Caller { public void Call() { SubjectERP erp =new(); for (var i = 1; i < 5; i++) { erp.AddProvider(new ApiProvider()); } erp.UpdateCommodity(); }}
复制代码

3.2 模板方法模式

  • 定义

Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Methods lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

定义一个操作中的算法框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法结构即可重定义该算法的某些特征步骤。

  • 基本方法 由子类实现的方法,并被模板方法调用。

  • 模板方法 可以有一个或者几个,一般是一个具体的方法,也是一个框架,实现对基本方法的调度,完成固定的逻辑。

  • 优点

  • 封装不变的部分,扩展可变的部分(把认为是不变的部分算法封装到父类实现,而可变的部分则可通过继承来继续扩展)

  • 提取公共代码,便于维护(修改父类中公共部分即可,不用去每一个子类维护相同的代码)

  • 行为由父类控制,子类实现(基本方法由子类实现,可以通过扩展的方式增加相应功能,符合开闭原则

  • 实现

父类(抽象层)建立框架,子类在重写父类部分方法(基本方法)后,再调用从父类继承的方法(模板方法),产生不同的结果。

  • UML 图

Template Pattern


  • 场景

假设有一个需求如下(并非完全真实场景):用户从手机第三方 APP(百度、微信、高德等)分享一个地址到车辆网 APP(可以和车机系统通信)上进行导航,核心流程基本一致:1、解析分享过来的地址(POI);2、判断是否满足发送到车机系统 3、创建最优路径(Trip) 4、发送车机系统

这里我们可以将核心流程(从第三方 APP 分享到车机系统),也就是模板方法模式中的“算法骨架”抽象出来,然后将不同 APP 的整个分享到发送车机的细节封装起来,他们之间相互独立。

public abstract class SendToCarTemplate{    //基本方法(迪米特法则:尽量使用protected 限制)    protected abstract string GetPoi(string address);    protected abstract string CreateTrip(string poi);  		//钩子函数(模板方法模式的扩展,用来约束模板方法的具体行为)    protected abstract bool EnableSendToCar(string poi);      //模板方法(算法框架,封装具体的逻辑、行为)    public void Send(string address)    {        string poi = GetPoi(address);        if (EnableSendToCar(poi))        {            string trip=CreateTrip(poi);            //Then call send-to-car api.        }    }}
//不同的对象(微信、百度、高德...)有不同的实现 //符合开闭原则:对扩展开放,对修改封闭public class BaiduProvider: SendToCarTemplate{ protected override string GetPoi(string provider)=> "东方明珠塔"; protected override string CreateTrip(string poi) => "从白玉兰广场到东方明珠塔"; protected override bool EnableSendToCar(string poi) => true;}
/// <summary>/// 调用端/// </summary>public class Client{ public void Send(string address) { //可以通过工厂模式获取SendToCar的对象 var provider=new BaiduProvider(); provider.Send(address);//调用父类中的算法架构
}}
复制代码


用户头像

青柚1943

关注

生命不息,代码不止。 2020.08.04 加入

老街坊,小弄堂,是属于那年代白墙黑瓦的淡淡的忧伤。

评论

发布
暂无评论
设计模式之禅(二)_设计模式_青柚1943_InfoQ写作社区