前言: 为什么要一次讲解这两个模式, 说点骚话: 因为比较简单 (*^_^*), 其实是他们两个有相似和有时候我们容易搞混概念.
讲到这两个设计模式与另外一个 "装饰者模式" 也有相似, 他们三个按照结构模式分类都属于 "结构性模式", 所有我们接下来就来看什么是适配器模式和外观模式.
另外装饰模式可以看我的另一篇博文→Head First 设计模式 -- 装饰者模式.
一, 适配器模式
适配器对应到我们现实生活中的例子, 最典型的就是插头接口适配器, 比如我们买的有些港版手机充电头是圆形三角插头, 而大陆的三角电源插板插不进去港版的插头.
这时候我们就会在某宝上买个转接头转换一下, 而这个转接头就是适配器, 用它来适配港版手机充电头让他能够插入到我们的电源插板里面.
在设计模式中这个适配器是什么, 用程序如何表现, 先让我举个栗子: 我们有一只鸭子, 一只鸡, 我们如何通过适配器转换鸭和鸡.
鸭子有很多种, 我们定义一个鸭子的接口, 然后以绿头鸭为例. 关于这个绿头鸭在策略模式也有用到, 可以看看我另一篇绿头鸭如何搅动策略模式→Head First 设计模式 -- 策略模式
- public interface Duck
- {
- // 叫
- public void Quack();
- // 飞
- public void Fly();
- }
- public class GreenDuck : Duck
- {
- public void Fly()
- {
- Console.WriteLine("绿头鸭, 飞");
- }
- public void Quack()
- {
- Console.WriteLine("绿头鸭, 呱呱叫");
- }
- }
同样我们定义一个鸡的接口, 和一只母鸡的类
- public interface Chicken
- {
- // 叫
- public void Gobble();
- // 飞
- public void Fly();
- }
- public class Hen : Chicken
- {
- public void Gobble()
- {
- Console.WriteLine("母鸡, 咯咯叫");
- }
- public void Fly()
- {
- Console.WriteLine("母鸡, 飞");
- }
- }
鸭子和母鸡的叫声不一样, 现在我们让母鸡来冒充鸭子, 利用适配器模式如何做. 直接看代码吧
- /// <summary>
- /// 母鸡适配器
- /// 适配母鸡让它变成鸭子
- /// </summary>
- public class HenAdapter : Duck
- {
- Chicken chicken;
- public HenAdapter(Chicken chicken)
- {
- this.chicken = chicken;
- }
- public void Quack()
- {
- // 调用母鸡咯咯叫
- chicken.Gobble();
- }
- public void Fly()
- {
- // 调用母鸡飞
- chicken.Fly();
- }
- }
测试母鸡适配器
如上我们使用母鸡适配器将母鸡适配成了鸭子, 鸭子也可以用适配器将鸭子适配成母鸡, 适配器模式定义:
适配器模式: 将一个类的接口, 装换成客户期望的另一个接口. 适配器让原本接口不兼容的类可以合作无间.
与适配器看起来相似的装饰者模式是包装对象的行为或责任, 装饰者被包装后可能会继续被包装, 他们不装换接口, 而适配器则一定会进行接口的转换.
适配的工作是将一个接口转换成另外一个接口, 虽然大多数适配器采取的例子都是让一个适配器包装一个被适配者, 但是有时候我们需要让一个适配器包装多个被适配者.
而这实际又涉及到另外一个模式, 就是外观模式, 我们常常将适配器模式和外观模式混为一谈, 那接着就来讲解外观模式.
二, 外观模式
外观模式以家庭影院为例, 家庭影院有许多组件构成, 比如: 显示屏, DVD, 音响, 灯光等等.
当我们要看电影的时候要打开显示屏, 打开 DVD, 打开音响, 关闭灯光等一系列动作, 将这些动作写成类方法的调用
- Screen screen = new Screen();
- DVD dvd = new DVD();
- SoundEngineer sound = new SoundEngineer();
- Light light = new Light();
- screen.Down();
- dvd.PlayDVD();
- sound.TurnOn();
- light.TurnOff();
可以看到每次我们要使用就要调用一篇这些方法, 如果要关闭呢, 我们也需要调用一篇. 而我们正需要的就是一个外观: 通过实现一个提供更合理的接口的外观类.
还是看代码吧
- public class HomeThreaterFacade
- {
- Screen screen;
- DVD dvd;
- SoundEngineer sound;
- Light light;
- public HomeThreaterFacade(Screen screen, DVD dvd, SoundEngineer sound, Light light)
- {
- this.screen = screen;
- this.dvd = dvd;
- this.sound = sound;
- this.light = light;
- }
- public void WatchMovie()
- {
- Console.WriteLine("开始播放电影......");
- screen.Down();
- dvd.PlayDVD();
- sound.TurnOn();
- light.TurnOff();
- }
- }
由于其他类比较简单就是一个打印输出, 我就不列出来了, 还有关闭方法同理也很简单就实现了.
还是测试一下效果:
外观模式定义
外观模式: 提供了一个统一的接口, 用来访问子系统中的一群接口. 外观定义了一个高层接口, 让子系统更容易使用.
外观模式遵循了一个设计原则
最少知识原则: 之和你的密友谈话.
这个原则希望我们在设计中, 不要让太多的类耦合在一起, 免得修改系统中一部分, 会影响其他部分. 而外观模式让用户不用关心全部子系统组件, 让客户变得简单有弹性. 我们可以在不影响客户的情况下升级外观模式里的组件, 而客户只有一个朋友, 也就是外观模式.
三, 适配器模式与外观模式区别
从上面例子我们也许会觉得适配器和外观模式之间的差异在于: 适配器包装一个类, 而外观可以代表许多类
但是实际它们的本质和作用并不是在于包装多少类, 适配器模式将一个或多个接口变成客户期望的一个接口, 我们一般适配一个类, 但是特殊需求也可以适配多个类来提供一个接口. 类是地, 一个外观也可以只争对一个复杂接口的类提供简化接口. 两中模式的差异在于他们的意图. 适配器模式意图是将接口装换成不同接口, 外观的意图是简化接口.
来源: https://www.cnblogs.com/SunSpring/p/11946631.html