桥接模式(Bridge Pattern)

    如果有一个N品牌的手机,它有个小游戏,我要玩游戏,程序应该如何写?

    客户端

    1. game.run();

    现在又有一个M品牌的手机,也是小游戏,客户端也可以调用,如何做?

    1. class HandSetGame
    2. {
    3. public virtual void Run()
    4. {
    5. }
    6. }

    M品牌手机游戏和N品牌手机游戏

    1. class HandSetMGame : HandSetGanme
    2. {
    3. public override void Run()
    4. {
    5. Console.WriteLine("运行M品牌手机游戏");
    6. }
    7. }
    8. class HandSetNGame : HandSetGanme
    9. {
    10. public override void Run()
    11. {
    12. Console.WriteLine("运行N品牌手机游戏");
    13. }
    14. }

    然后,由于手机都需要通讯录功能,于是N品牌和M品牌都增加了通讯录的增删该查功能,如何处理?

    1. //手机品牌
    2. class HandSetBrand
    3. {
    4. public virtual void run()
    5. {
    6. }
    7. }

    下属的各自通讯录类和游戏类

    1. //手机品牌M的游戏
    2. class HandSetBrandMGame:HandSetBrandM
    3. {
    4. public override void Run()
    5. {
    6. Console.WriteLine("运行M品牌手机游戏");
    7. }
    8. }
    9. //手机品牌N的游戏
    10. class HandSetBrandMGame:HandSetBrandM
    11. {
    12. public override void Run()
    13. {
    14. Console.WriteLine("运行N品牌手机游戏");
    15. }
    16. }
    17. //手机品牌M的通讯录
    18. class HandSetBrandMAddressList:HandSetBrandM
    19. {
    20. {
    21. }
    22. }
    23. //手机品牌N的
    24. class HandSetBrandMAddressList:HandSetBrandM
    25. {
    26. public override void Run()
    27. {
    28. Console.WriteLine("运行N品牌手机通讯录");
    29. }
    30. }

    客户端调用代码

    1. static void Main(strring[] args)
    2. {
    3. HandSetBrand ab;
    4. ab = new HandSetBrandMAddressList();
    5. ab.Run();
    6. ab = new HandSetBrandNAddressList();
    7. ab.Run();
    8. ab = new HandSetBrandMGame();
    9. ab.Run();
    10. ab = new HandSetBrandNGame();
    11. ab.Run();
    12. Console.Read();
    13. }

    如果我现在需要每个品牌都增加一个MP3音乐功能,如何做?还增加子类?


    合成(Composition)/聚合(Aggregation)复用原则,尽量使用合成/聚合,尽量不要使用类继承。


    聚合表示一种弱的’拥有’关系,体现的是A对象可以包含B对象,但是B对象不是A对象的一部分。合成则是一种强的’拥有’关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。

    比如说 大雁有翅膀,大雁和翅膀是部分和整体的关系,并且它们生命周期是一样的,于是它们就是合成关系。而大雁是群居动物,所以每只大雁都属于一个雁群,一个雁群可以有很多大雁,所以大雁和雁群是聚合关系。

    优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。

    像’游戏’,’通讯录’,’MP3音乐’,如果我们可以让其分离与手机的耦合,那么可以大大减少面对新需求改动过大的不合理情况。

    松耦合的程序

    1. //手机软件
    2. abstract class HandsetSoft
    3. {
    4. public abstract void Run();
    5. }

    游戏,通讯录等具体类

    1. //手机游戏
    2. class HandsetGame : HandSetSoft
    3. {
    4. public override void Run()
    5. {
    6. Console.WriteLine("运行手机游戏");
    7. }
    8. }
    9. //手机通讯录
    10. class HandsetAddressList : HandSetSoft
    11. {
    12. public override void Run()
    13. {
    14. Console.WriteLine("运行手机通讯录");
    15. }
    16. }

    品牌N品牌M具体类

    1. {
    2. public override void Run()
    3. {
    4. soft.Run();
    5. }
    6. }
    7. //手机品牌M
    8. class HandSetBrandM: HandBrand
    9. {
    10. public override void Run()
    11. {
    12. soft.Run();
    13. }
    14. }
    1. static void Mian(string[] args)
    2. {
    3. HandSetBrand ab;
    4. ab = new HandSetBrandN();
    5. ab.setHandSetSoft(new HandSetGame());
    6. ab.run();
    7. ab.setHandSetSoft(new HandSetAddressList());
    8. ab.run();
    9. ab = new HandSetBrandM();
    10. ab.setHandSetSoft(new HandSetGame());
    11. ab.run();
    12. ab.setHandSetSoft(new HandSetAddressList());
    13. ab.run();
    14. Console.Read();
    15. }

    现在我们要再加个功能 比如说MP3功能,只要增加这个类就好了,不会影响其它任何类。

    1. //手机MP3播放
    2. class HandsetMP3 : HandSetSoft
    3. {
    4. public override void Run()
    5. {
    6. Console.WriteLine("运行手机MP3");
    7. }
    8. }

    如果要增加S品牌,只需要增加一个品牌子类就可以了。

    1. //手机品牌S
    2. class HandSetBrand: HandSetBrand
    3. {
    4. public override void Run()
    5. {
    6. soft.Run();
    7. }
    8. }

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

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

    桥接模式基本代码

    桥接模式 - 图1

    桥接模式把两个角色之间的继承关系改为聚合关系,从而使二者可以各自独立的变化。把原来在基类的实现化细节抽象出来,再构造到一个实现化的结构中,然后把原来的基类改造成一个抽象化的等级结构,这样就实现了系统在多个维度上的独立变化。