【设计模式】桥接模式
作者:互联网
应用场景
桥接模式的一个常见使用场景就是替换继承。我们知道,继承拥有很多优点,比如,抽象、封装、多态等,父类封装共性,子类实现特性。继承可以很好的实现代码复用(封装)的功能,但这也是继承的一大缺点。 因为父类拥有的方法,子类也会继承得到,无论子类需不需要,这说明继承具备强侵入性(父类代码侵入子类),同时会导致子类臃肿。因此,在设计模式中,有一个原则为优先使用组合/聚合,而不是继承。
现实生活中我们看见桥接
这两个字可能在路由器配置时候看见叫路由桥接
。其实概念比较相似,路由器的桥接其实就是2个路由器把其中一个路由器接入到另外一个路由器下面。这两个路由器都可以对外提供wifi信号,终端(手机,电脑)相当于子类都可以用这两个路由器发出的wifi信号。代码中的桥接就是两个抽象接口其中一个抽象接口接入到另一个抽象接口中,二者都有对应的实现类,这样就可以编程笛卡尔积组合,进而增强实用性和扩展性。
我认为如果程序设计上出现笛卡尔积的情况时就要考虑采用该设计模式了
代码示例
我们列举一个实际的场景来用代码实现一下,实际感受一下实际应用的场景,我们买奶茶的时候可供选择有口味,容量也就是大杯小杯。比如有热奶茶和冰奶茶,对应的有大杯和小杯。这样就出现了笛卡尔积的情况组合。
- 热的大杯奶茶
- 热的小杯奶茶
- 凉的大杯奶茶
- 凉的小杯奶茶
我们先用if-else来实现一下。
///抄袭的,所以先用java 等实列,会改C# public class MilkTeaController { private Logger logger = LoggerFactory.getLogger(MilkTeaController.class); /** * 来杯奶茶 * * @param type 1热的 2凉的 * @param modeType 1大杯 2小杯 * @return */ public boolean getMilkTea(int type, int modeType) { if (1 == type) { //热奶茶 if (1 == modeType) { logger.info("来个热的大杯奶茶"); } else if (2 == modeType) { logger.info("来个热的小杯奶茶"); } } if (2 == type) { //凉奶茶 if (1 == modeType) { logger.info("来个凉的大杯奶茶"); } else if (2 == modeType) { logger.info("来个凉的小杯奶茶"); } } return true; } }
如上代码这么写的绝对不在少数。如果像上面这样写能不能实现正常业务,绝对没问题,但是如果要进行扩展就会写更多的if-else。到后来写着写着就没办法维护了。有人提出我们是面向接口编程我们可以进行抽象一层出来就没有这么多if-else了。这样写:
- 抽象一个奶茶类
public interface IMilkTea { //点个奶茶 void orderMilkTea(int modeType);
public string Name
}
- 热奶茶实现
public class HotMilkTea implements IMilkTea { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public void orderMilkTea(int modeType) { if (1 == modeType) { logger.info("来个热的大杯奶茶"); } else if (2 == modeType) { logger.info("来个热的小杯奶茶"); } } }
- 凉奶茶实现
public class ColdMilkTea implements IMilkTea { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public void orderMilkTea(int modeType) { if (1 == modeType) { logger.info("来个凉的大杯奶茶"); } else if (2 == modeType) { logger.info("来个凉的小杯奶茶"); } } }
这样写,我只能说:嗯,有内味了。但是改造的不彻底。我们用桥接模式改造一下看看有哪些便利:
====================C# 代码实现部分 ========================
先化成UML类图
1、我们做第一个抽象,抽象一个热或者凉的概念,代码如下:
public abstract class MilkTea { protected ICup icup; public void SetCup(ICup cup) { icup = cup; } public abstract void GetMilk(); }
上面的这个抽象类中介入了一个接口对象ICup。这个就是整个桥接的核心,也就是桥接的"桥"的概念。
2、我们接着做第二个抽象。将大小杯进行抽象,代码:
public interface ICup { public void TakeMilk(int temperature); }
3、接下来我们对具体抽象类进行精细化实现
热奶茶
public class HotMilkTea : MilkTea { public override void GetMilk() { this.icup.TakeMilk(60);//60度奶茶 Console.WriteLine("热奶茶做好了"); } }
凉奶茶
public class ColdMilkTea : MilkTea { public override void GetMilk() { this.icup.TakeMilk(10);//10度奶茶 Console.WriteLine("凉奶茶做好了"); } }
4、具体类实现
大杯
public class GrandeCup : ICup { public string Name = "大杯"; public void TakeMilk(int temperature) { Console.WriteLine($"{Name} 的 {temperature}度奶茶是谁的"); } }
中杯
public class TallCup : ICup { public string Name = "中杯"; public void TakeMilk(int temperature) { Console.WriteLine($"{Name} 的 {temperature}度奶茶是谁的"); } }
小杯
public class ShortCup : ICup { public string Name = "小杯"; public void TakeMilk(int temperature) { Console.WriteLine($"{Name} 的 {temperature}度奶茶是谁的"); } }
好了,这样我们就定义好了,我们用个客户端测试一下:
using MilkTeaShop.Cup; using MilkTeaShop.Tea; MilkTea milkTea= new ColdMilkTea(); milkTea.SetCup(new ShortCup()); milkTea.GetMilk(); milkTea = new HotMilkTea(); milkTea.SetCup(new TallCup()); milkTea.GetMilk();
输出结果
小杯 的 10度奶茶是谁的
凉奶茶做好了
中杯 的 60度奶茶是谁的
热奶茶做好了
这样如果以后推出温杯奶茶,那我们无需改动原有逻辑只需要增加一个类:
public class WarmMilkTea : MilkTea { public override void GetMilk() { this.icup.TakeMilk(45);//45度奶茶 Console.WriteLine("温奶茶做好了"); } }
就能很好的满足需求了。
改进作者:小林野夫 原作者:我是大明哥
链接:https://juejin.cn/post/6970183473935958029
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
标签:桥接,void,模式,class,modeType,奶茶,logger,设计模式,public 来源: https://www.cnblogs.com/cdaniu/p/16399021.html