22.1 凭什么你的游戏我不能玩
22.2 紧耦合的程序演化
namespace 桥接模式 { class Program { static void Main(string[] args) { HandsetBrand ab; ab = new HandsetBrandMAddressList(); ab.Run(); ab = new HandsetBrandMGame(); ab.Run(); ab = new HandsetBrandNAddressList(); ab.Run(); ab = new HandsetBrandNGame(); ab.Run(); Console.Read(); } } //手机品牌, class HandsetBrand { public virtual void Run() { } } //手机品牌M, class HandsetBrandM : HandsetBrand { } //手机品牌N, class HandsetBrandN : HandsetBrand { } //手机品牌M的游戏, class HandsetBrandMGame : HandsetBrandM { public override void Run() { Console.WriteLine("运行M品牌手机游戏"); } } //手机品牌N的游戏, class HandsetBrandNGame : HandsetBrandN { public override void Run() { Console.WriteLine("运行N品牌手机游戏"); } } //手机品牌M的通讯录, class HandsetBrandMAddressList : HandsetBrandM { public override void Run() { Console.WriteLine("运行M品牌手机通讯录"); } } //手机品牌N的通讯录, class HandsetBrandNAddressList : HandsetBrandN { public override void Run() { Console.WriteLine("运行N品牌手机通讯录"); } } }
增加新的手机品牌S,它也必须有游戏,通讯录,MP3音乐播放功能,如何处理?那就要增加手机品牌S类和三个下属功能子类,过于麻烦,
很多情况下用继承会带来麻烦,比如,对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现,子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化,当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类须重写或被其它更适合的类替换,这种依赖关系限制了灵活性并最终限制了复用性,
22.3 合成 聚合复用原则
尽量使用合成/聚合,尽量不要使用类继承,
聚合表示一种弱的“拥有”关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分,合成则是一种强的“拥有”关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样,
合成/聚合复用原则的好处是,优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上,这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物,
刚才的例子需要学会用对象的职责,而不是结构来考虑问题,
抽象出手机品牌类与手机软件类,手机品牌包含手机软件,但软件并不是品牌的一部分,所以它们之间是聚合关系,
22.4 松耦合的程序
namespace 桥接模式 { class Program { static void Main(string[] args) { HandsetBrand ab; ab = new HandsetBrandN(); ab.SetHandsetSoft(new HandsetGame()); ab.Run(); ab.SetHandsetSoft(new HandsetAddressList()); ab.Run(); ab = new HandsetBrandM(); ab.SetHandsetSoft(new HandsetGame()); ab.Run(); ab.SetHandsetSoft(new HandsetAddressList()); ab.Run(); Console.Read(); } } //抽象手机软件, abstract class HandsetSoft { public abstract void Run(); } //手机游戏, class HandsetGame : HandsetSoft { public override void Run() { Console.WriteLine("运行手机游戏"); } } //手机通讯录, class HandsetAddressList : HandsetSoft { public override void Run() { Console.WriteLine("运行手机通讯录"); } } ////手机MP3播放, //class HandsetMP3 : HandsetSoft //{ // public override void Run() // { // Console.WriteLine("运行手机MP3播放"); // } //} //抽象手机品牌, abstract class HandsetBrand { protected HandsetSoft soft; //设置手机软件, public void SetHandsetSoft(HandsetSoft soft) { this.soft = soft; } //运行, public abstract void Run(); } //手机品牌N, class HandsetBrandN : HandsetBrand { public override void Run() { soft.Run(); } } //手机品牌M, class HandsetBrandM : HandsetBrand { public override void Run() { soft.Run(); } } ////手机品牌S, //class HandsetBrandS : HandsetBrand //{ // public override void Run() // { // soft.Run(); // } //} }
22.5 桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立的变化,
什么叫抽象与它的实现分离,这并不是说,让其抽象类与其派生类分离,因为这没有任何意义,实现指的是抽象类和它的派生类用来实现自己的对象,就刚才例子而言,手机既可以按照品牌来分类,也可以按照功能来分类,
22.6 桥接模式的基本代码
namespace 桥接模式 { class Program { static void Main(string[] args) { Abstraction ab = new RefinedAbstraction(); ab.SetImplementor(new ConcreteImplementorA()); ab.Operation(); ab.SetImplementor(new ConcreteImplementorB()); ab.Operation(); Console.Read(); } } //抽象实现者类, abstract class Implementor { public abstract void Operation(); } class ConcreteImplementorA : Implementor { public override void Operation() { Console.WriteLine("具体实现A的方法执行"); } } class ConcreteImplementorB : Implementor { public override void Operation() { Console.WriteLine("具体实现B的方法执行"); } } class Abstraction { protected Implementor implementor; public void SetImplementor(Implementor implementor) { this.implementor = implementor; } public virtual void Operation() { implementor.Operation(); } } class RefinedAbstraction : Abstraction { public override void Operation() { implementor.Operation(); } } }
桥接模式就是,实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让他们独立变化,减少它们之间的耦合,
22.7 我要开发好游戏