桥接模式(21)

今天我们来讲一下桥接模式。

一、案例

我有N牌子的一个手机,需要运行一款游戏软件。咱们用简单的控制台应用程序来实现一下。

 1     /// <summary>
 2     /// N品牌的手机中的游戏
 3     /// </summary>
 4     class HandsetNGame
 5     {
 6         public void Run()
 7         {
 8             Console.WriteLine("运行N品牌手机游戏");
 9         }
10     }

客户端调用:

1         public static void Main()
2         {
3             HandsetNGame n = new HandsetNGame();
4             n.Run();
5             Console.ReadKey();
6         }

二、演绎

1、第一步演绎:

如果我不仅有N品牌的手机,还有M品牌的手机也需要运行这款游戏软件,怎么办?

我们可以将运行游戏软件抽象出一个父类,让N,M品牌的手机继承这个父类。代码如下:

 1     /// <summary>
 2     /// 父类
 3     /// </summary>
 4     class HandsetGame
 5     {
 6         public virtual void Run()
 7         {
 8 
 9         }
10     }
11     /// <summary>
12     /// 子类
13     /// </summary>
14     class HandsetNGame : HandsetGame
15     {
16         public override void Run()
17         {
18             Console.WriteLine("运行N品牌手机游戏");
19         }
20     }
21     /// <summary>
22     /// 子类
23     /// </summary>
24     class HandsetMGame : HandsetGame
25     {
26         public override void Run()
27         {
28             Console.WriteLine("运行M品牌手机游戏");
29         }
30     }

客户端调用:

1         public static void Main()
2         {
3             HandsetGame gameM = new HandsetMGame();
4             HandsetGame gameN = new HandsetNGame();
5             gameM.Run();
6             gameN.Run();
7             Console.ReadKey();
8         }

2、第二步演绎

还有一个问题是,手机不仅能玩游戏,还要有通讯录的功能,也就是说N,M品牌的手机都有通讯录的功能,那么我们该怎么做呢?

小伙伴们说,这容易啊,跟第一步一样,抽象出一个通讯录的父类,让N,M品牌手机通讯录继承这个父类即可。代码如下:

 1     /// <summary>
 2     /// 父类
 3     /// </summary>
 4     class HandsetBrand
 5     {
 6         public virtual void Run()
 7         {
 8             
 9         }
10     }
11     /// <summary>
12     /// 子类
13     /// </summary>
14     class HandNsetBrand:HandsetBrand
15     {
16         public override void Run()
17         {
18             Console.WriteLine("运行N品牌手机通讯录");
19         }
20     }
21     /// <summary>
22     /// 子类
23     /// </summary>
24     class HandMsetBrand:HandsetBrand
25     {
26         public override void Run()
27         {
28             Console.WriteLine("运行M品牌手机通讯录");
29         }
30     }

客户端调用是类似的,在此不写代码了。

好,那么问题来了,我们手机不仅有游戏,通讯录功能,还有很多很多的功能,例如,照相,彩信等等等等,照这样下去,我们这种设计将会让类异常的多,项目异常的庞大,出现这种情况,我们不禁怀疑我们的这种设计是不是出现了问题,如果出现了问题,我们改用什么方式解决呢?

对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现,子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或者被其他更适合的类替换,这种依赖关系限制了灵活性并最终限制了复用性。

在这里首先我们来讲一个设计原则,合成/聚合复用原则。

合成/聚合复用原则,尽量使用合成/聚合尽量不要使用类继承,聚合表示一种弱的‘拥有’关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;合成表示一种强的‘拥有’关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。打个比方,大雁有两只翅膀,翅膀和大雁就是部分和整体的关系,他们的生命周期是相同的,是合成。大雁和雁群,是聚合关系。

好,本着合成/聚合复用原则,我们重新来设计一下我们案例中的代码

 1     //手机软件
 2     abstract class HandsetSoft
 3     {
 4         public abstract void Run();
 5     }
 6     //手机游戏
 7     class HandsetGame:HandsetSoft
 8     {
 9         public override void Run()
10         {
11             Console.WriteLine("运行手机游戏");
12         }
13     }
14     //手机通讯录
15     class HandsetAddressList:HandsetSoft
16     {
17         public override void Run()
18         {
19             Console.WriteLine("运行手机通讯录");
20         }
21     }
22     //手机品牌
23     abstract class HandsetBrand
24     {
25         protected HandsetSoft soft;
26         //品牌需要关注软件,所以可在机器中安装软件,以备运行
27         public void SetHandsetSoft(HandsetSoft soft)
28         {
29             this.soft = soft;
30         }
31         //运行
32         public abstract void Run();
33     }
34     //具体的手机品牌N
35     class HandsetBrandN:HandsetBrand
36     {
37         public override void Run()
38         {
39             soft.Run();
40         }
41     }
42     //具体的手机品牌M
43     class HandsetBrandM:HandsetBrand
44     {
45         public override void Run()
46         {
47             soft.Run();
48         }
49     }

客户端调用:

 1         public static void Main()
 2         {
 3             HandsetBrand ab;
 4             ab = new HandsetBrandN();
 5             ab.SetHandsetSoft(new HandsetGame());
 6             ab.Run();
 7 
 8             ab.SetHandsetSoft(new HandsetAddressList());
 9             ab.Run();
10 
11             ab = new HandsetBrandM();
12             ab.SetHandsetSoft(new HandsetGame());
13             ab.Run();
14 
15             ab.SetHandsetSoft(new HandsetAddressList());
16             ab.Run();
17             Console.ReadKey();
18         }

以上就是我们要将的一种设计模式:桥接模式。

桥接模式,将抽象部分与他的实现部分分离,使他们都可以独立的变化。

这里解释一下:什么叫抽象与他的实现分离?这并不是说,让抽象类与其派生类分离,因为这没有任何的意义,实现指的是抽象类和他的派生类用来实现自己的对象。

真正的理解的设计原则,很多的设计模式其实就是设计原则的使用,在不知不觉中,我们就使用了很多的设计模式了。

今天的桥接模式我们先讲到这里,下一篇我们讲 命令模式


 本系列将持续更新,喜欢的小伙伴可以点一下关注和推荐,谢谢大家的支持

posted @ 2017-02-14 14:14  萌萌丶小魔王  阅读(293)  评论(0编辑  收藏  举报