美文网首页
常用的结构型设计模式(C#举例)

常用的结构型设计模式(C#举例)

作者: suoxd123 | 来源:发表于2020-03-25 16:25 被阅读0次

    概述

    1. 代理模式:代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。
    2. 装饰器模式:装饰者模式在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器的嵌套使用。
    3. 适配器模式:适配器模式是一种事后的补救策略。适配器提供跟原始类不同的接口,而代理模式、装饰器模式提供的都是跟原始类相同的接口。

    代理模式

    它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。

    1. 一般情况下,让代理类和原始类实现同样的接口
    2. 如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的,可以通过让代理类继承原始类的方法来实现代理模式
    3. 常用在业务系统中开发非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志等
    4. 将附加功能与业务功能解耦,放到代理类统一处理,方便让程序员只关注业务方面的开发
    // author: suoxd123@126.com
    public interface IRunner{
    // 接口也可以替换成抽象类
      void run();
    }
    public class Marathon : IRunner {
      public void run() { //... }
    }
    public class CrossCountryProxy : IRunner {
      private IRunner runner;
      public CrossCountryProxy(IRunner runner) {
        this.runner = runner;
      }
      
      public void run() {
        // 新添加的代理逻辑
        runner.run();
        // 新添加的代理逻辑
      }
    }
    

    装饰器模式

    装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能,这也是判断是否该用装饰器模式的一个重要的依据。
    从代码看,两种模式完全一样,只是其设计的侧重点不同,简单来讲:

    1. 代理:偏重因自己无法完成或自己无需关心,需要他人干涉事件流程。
    2. 装饰:偏重对原对象功能的扩展,扩展后的对象仍是是对象本身。
    // author: suoxd123@126.com
    public interface IRunner{
    // 接口也可以替换成抽象类
      void run();
    }
    public class Marathon : IRunner {
      public void run() { //... }
    }
    public class CrossCountryDecorator : IRunner {
      private IRunner runner;
      public CrossCountryDecorator(IRunner runner) {
        this.runner = runner;
      }
      
      public void run() {
        // 功能增强代码
        runner.run();
        // 功能增强代码
      }
    }
    

    适配器模式

    用来做适配的,它将不兼容的接口转换为可兼容的接口,常用有两种实现方式:

    1. 类适配器:使用继承关系来实现
    2. 对象适配器:使用组合关系来实现

    判断使用哪个的标准一般有两个,一个是 Adaptee 接口的个数,另一个是 Adaptee 和 ITarget 的契合程度

    1. 如果 Adaptee 接口并不多,那两种实现方式都可以。
    2. 如果 Adaptee 接口很多,而且 Adaptee 和 ITarget 接口定义大部分都相同,那我们推荐使用类适配器,因为 Adaptor 复用父类 Adaptee 的接口,比起对象适配器的实现方式,Adaptor 的代码量要少一些。
    3. 如果 Adaptee 接口很多,而且 Adaptee 和 ITarget 接口定义大部分都不相同,那我们推荐使用对象适配器,因为组合结构相对于继承更加灵活。

    使用适配器模式的场景一般有以下5种情况:

    1. 封装有缺陷的接口设计
    2. 统一多个类的接口设计
    3. 替换依赖的外部系统
    4. 兼容老版本接口
    5. 适配不同格式的数据
    // author: suoxd123@126.com
    public interface IRunner {
      void walk();
      void run();
    }
    
    public class CrossCountry {
      public void run(){}
      public void eat(){}
    }
    
    // 类适配器: 基于继承
    public class SportsAdaptor : CrossCountry, IRunner {
      public void walk() {
        super.eat();
        //其它行为
      }
      // 跟对象适配器最大的不同点:
      // 这里run可以不实现,直接继承自CrossCountry
    }
    
    // 对象适配器:基于组合
    public class SportsAdaptor : IRunner  {
      private CrossCountry crossCountry;
      
      public Adaptor(CrossCountry crossCountry) {
        this.crossCountry = crossCountry;
      }
      
      public void walk() {
        this.crossCountry.eat(); //委托给Adaptee    
        //其它行为
      }
      
      //这里run需要显示实现
      public void run() {
        this.crossCountry.run();
      }
    }
    

    相关文章

      网友评论

          本文标题:常用的结构型设计模式(C#举例)

          本文链接:https://www.haomeiwen.com/subject/dilxuhtx.html