结构型设计模式

创建型设计模式主要是为了解决创建对象的问题,而结构型设计模式则是为了解决已有对象的使用问题。

适配器模式

适配器模式比较好理解,因为在我们的日常生活中就很常见,如耳机转换线、充电器适配器、插座等,举个最常见的例子:

设计模式详解之结构型设计模式——适配器、装饰器

插座就是个适配器,将一个接口扩展为多个接口,将墙上的双孔接口转换为三孔接口。而这也就是适配器的作用:将一个接口转换为用户期望的另一个接口。

适配器的使用场景:

  • 需要使用第三方SDK的核心功能,但其接口或者功能不符合需求,这时可以使用适配器对其进行兼容和扩展
  • 随着业务发展,旧接口已经不能满足需求,但重写代价又太大,这时可以使用适配器对接口功能进行扩展

注意:适配器是对已有资源进行兼容和扩展,属于一种折中的方式,如果可以的话,尽量重构系统而不是使用适配器

继承器的实现有两种方式:继承组合,基于合成复用的原则,组合优于继承,所以应尽量使用组合的方式实现适配器。类图如下:

设计模式详解之结构型设计模式——适配器、装饰器

实现代码:

    //已有的旧接口,不兼容于现在的系统     public interface IAmericanElectrictService     {         int Get110VElectric();     }          //adaptee,需要适配的SDK     public class AmericanElectrictService : IAmericanElectrictService     {         public int Get110VElectric()         {             Console.WriteLine("美国的电压是110v,只能提供110V的电压");             return 110;         }     }          //已有接口,现在的系统需要使用这个接口     public interface IChineseElectricService     {         int Get220VElectric();     }          //适配器,采取组合的方式     //这里是为了适配已有接口,所以实现了这个接口     public class AdapterPattern : IChineseElectricService     {         private readonly IAmericanElectrictService _service;          public AdapterPattern(IAmericanElectrictService service)         {             this._service = service;         }         public int Get220VElectric()         {             var electric = this._service.Get110VElectric();             Console.WriteLine("劈里啪啦劈里啪啦,经过一番操作,现在电压转换为220V的了");             return electric + 110;         }     }          //使用适配器,将110V电压转换成220V     public class AdapterRunner : IRunner     {         public void Run()         {             //实际情况中,adaptee有可能是已有SDK,有可能是interface,通过IOC容器对应具体实现类             var americanElectric = new AmericanElectrictService();             var electric = americanElectric.Get110VElectric();             Console.WriteLine($"获得了{electric}V电压");             Console.WriteLine("使用适配器");             var adapter = new AdapterPattern(americanElectric);             electric = adapter.Get220VElectric();             Console.WriteLine($"使用适配器后获得了{electric}V电压");         }     }     //输出     //------------------------------------     //美国的电压是110v,只能提供110V的电压     //获得了110V电压     //使用适配器     //美国的电压是110v,只能提供110V的电压     //劈里啪啦劈里啪啦,经过一番操作,现在电压转换为220V的了     //使用适配器后获得了220V电压

总结

优点:

  • 可以扩展和兼容现有类,灵活性高
  • 提高了类的复用,原本不能使用的类适配后能使用

缺点:

  • 适配器本质是套一层,如果使用过多,可能导致系统混乱,甚至出现套中套的复杂情况

装饰器模式

利用继承和组合,在不改变现有结构的情况下对功能进行扩展的模式称为装饰器模式

装饰器模式和适配器模式很像,但侧重点不一样。适配器的重心在于兼容已有系统,而装饰器的重心在于功能扩展。装饰器的类图如下:

设计模式详解之结构型设计模式——适配器、装饰器

上图中,基础装饰器继承抽象类,每个装饰器继承前一个装饰器,一步一步添加功能,并且所有装饰器都用到具体实现类,因为需要扩展具体功能。

这里其实就能看出一些装饰器和适配器的区别,适配器和装饰器都使用组合来包装已有类,不同的是装饰器用到了继承。装饰器的核心原则是里氏替换原则,即父类一定能被子类替换而不影响现有代码。实现代码如下:

//抽象基础类 public abstract class AbstractStudent {     public abstract void Study(); }  //具体实现类 public class Student : AbstractStudent {     public override void Study()     {         Console.WriteLine("我正在学习!!!");     } }   //基础装饰器,什么也不做 //注意,这里标记为抽象类,此后的装饰器以此为基础 public abstract class BaseDecorator : AbstractStudent {     private readonly AbstractStudent _student;     public BaseDecorator(AbstractStudent student)     {         this._student = student;     }     //这里使用override还是Virtual取决于AbstractStudent基础类是抽象类还是接口     public override void Study()     {         this._student.Study();     } }  //前缀装饰器,在调用具体功能前做点什么  public class PreDecorator : BaseDecorator {     public PreDecorator(AbstractStudent student) : base(student)     {     }     public override void Study()     {         Console.WriteLine("学习前看会儿小说");         base.Study();     } }  //后缀装饰器,在调用具体功能后做点什么 public class NextDecorator : PreDecorator {     public NextDecorator(AbstractStudent student) : base(student)     {     }     public override void Study()     {         base.Study();         Console.WriteLine("学习辛苦啦,奖励自己一包辣条");     } }  //测试代码 public class DecoratorRunner : IRunner {     public void Run()     {         Console.WriteLine("没有用装饰器的基本功能:");         var student = new Student();         student.Study();         Console.WriteLine();                  Console.WriteLine("使用前缀装饰器在基础功能之前做点什么");         var preDecorator = new PreDecorator(student);         preDecorator.Study();         Console.WriteLine();                  Console.WriteLine("使用后缀装饰器在前缀装饰器功能之后做点什么");         //注意:这里传入的前缀装饰器,在前缀装饰器的基础之上做扩展         var nextDecorator = new NextDecorator(student);         nextDecorator.Study();     } }  //输出:   //没有用装饰器的基本功能: //我正在学习!!! // //使用前缀装饰器在基础功能之前做点什么 //学习前看会儿小说 //我正在学习!!! // //使用后缀装饰器在前缀装饰器功能之后做点什么 //学习前看会儿小说 //我正在学习!!! //学习辛苦啦,奖励自己一包辣条

可以看出,装饰器其实就是利用组合+继承(实现)+override不断包装和更新对象,使其功能得到扩展。装饰器是用于替换继承的设计模式,主要使用场景如下:

  • 想扩展实现类的功能,又不想添加太多子类
  • 需要动态增加和撤销功能(例如游戏技能)

装饰器的优点在于灵活,耦合性低,且不会改变现有结构。缺点则是嵌套过多会增加系统复杂度。

热门文章

同城免费领养宠物怎么领取 同城免费领养宠物怎么领取的

摘要: 大家好,今天小编关注到一个比较有意思的话题,就是关于同城免费领养宠物怎么领取的问题,于是小编就整理了4个相关介绍同城免费领养宠物怎么领取的解答,让我们一起看看吧。58上怎么发布免费

1月10日更新18.5M/S,2025年最新高速V2ray/Clash/SSR/Shadowrocket订阅链接免费节点地址分享

这一次的节点更新覆盖了欧洲、新加坡、韩国、日本、加拿大、香港、美国等地区,最高速度可达18.5 M/S。只需复制下方的Clash/v2ray订阅链接,在客户端添加后即可正常使用。

西安火车站附近的旅游景点有哪些(西安火车站附近有什么好玩的?)

今天蝶侠小编整理了火车站(西安火车站附近的景点)相关信息,希望在这方面能够更好的大家。本文目录一览:1、西安火车站附近景点2、西安火车站附近的景点3、西安北站附近的旅游景点 西安火车站附近景点

设计模式详解之结构型设计模式——适配器、装饰器

结构型设计模式 创建型设计模式主要是为了解决创建对象的问题,而结构型设计模式则是为了解决已有对象的使用问题。 适配器模式 适配器模式比较好理解,因为在我们的日常生活中就很常见,如耳机转换线、充电器适配

1月15日更新18.4M/S,2025年最新高速Shadowrocket/Clash/V2ray/SSR订阅链接免费节点地址分享

这一次的节点更新覆盖了美国、香港、加拿大、新加坡、欧洲、日本、韩国等地区,最高速度可达18.4 M/S。只需复制下方的Clash/v2ray订阅链接,在客户端添加后即可正常使用。

PowerShell中的复制项目用于什么?

PowerShell cmdlet中的Copy-Item用于将项目从一个位置复制到同一命名空间中的另一位置。在这里,命名空间的含义是,您可以将项目从文件复制到其他文件夹,但不能将文件复制到注册表或证书

1月18日更新21.5M/S,2025年最新高速Shadowrocket/SSR/Clash/V2ray订阅链接免费节点地址分享

这一次的节点更新覆盖了欧洲、美国、加拿大、新加坡、韩国、香港、日本等地区,最高速度可达21.5 M/S。只需复制下方的Clash/v2ray订阅链接,在客户端添加后即可正常使用。

中国宠物用品市场(中国宠物用品市场在哪里)

摘要: 本篇文章给大家谈谈中国宠物用品市场,以及中国宠物用品市场在哪里对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。本文目录一览:1、宠物用品哪里最好?2、... 本

动物疫苗是什么单位(动物疫苗的生产原料有哪些)

摘要: 本篇文章给大家谈谈动物疫苗是什么单位,以及动物疫苗的生产原料有哪些对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。本文目录一览:1、给狗打针是什么部门2、...

饲料搅拌粉碎机安装图(饲料粉碎搅拌机百科)

摘要: 今天给各位分享饲料搅拌粉碎机安装图的知识,其中也会对饲料粉碎搅拌机百科进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览:1、选配与安装小型饲料加.

归纳