1. 紧耦合的程序演化
代码结构图:
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品牌手机通讯录");
}
}
A: 如果现在需要每个品牌都增加一个MP3音乐播放功能,你如何做?
B: 那就在每个品牌下面都增加一个子类。
A: 如果新增一个手机品牌S,岂不是更炸。
另一个结构图:
B: 这样子,要是增加手机功能或品牌都会产生很大的影响。
A: 很多情况下,用继承会带来麻烦。比如,对象的继承关系是在编译时就定义好了,所有无法在运行时改变从父类继承的实现。子类实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要的复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。
A: 在面向对象设计中,我们还有一个很重要的设计原则,那就是合成/集合复用原则。即优先使用对象合成/复用,而不是类的继承。
2. 合成/集合原则
尽量使用合成/集合,尽量不要使用类继承。
集合表示一种弱的'拥有'关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;合成则是一种强的'拥有'关系,体现了严格的部分和整体关系,部分和整体的生命周期一样。
好处是,优先使用对象的合成/集合将有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小的规模,并且不太可能增长不可控制的庞然大物。
B: 像游戏,通讯录等这些功能都是软件,如果我们可以让其分离与手机的耦合,那么就可以大大减少面对新需求时改动过大的不合理情况。
A: 手机品牌和手机软件之间的关系呢?
B: 手机品牌包含手机软件,但软件并不是品牌额一部分,所有它们之间是耦合关系。
3. 松耦合的程序
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 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();
}
}
//手机软件
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播放");
}
}
B: 开放-封闭原则。这样的设计显然不会修改原来的代码,而只是扩张类就行了。
A: 盲目使用继承当然就会造成麻烦,而其本质原因主要是什么。
B: 我想应该是,继承是一种强耦合的结构。父类变,子类必须改变。
A: 咋'is-a'关系的时候在考虑继承,而不是任何时候都去用。
4. 桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
A: 什么叫抽象与它的实现分离,这并不是说,让抽象类与其派生类分离,因为这没有任何意义。实现指的是抽象类和它的派生类用来实现自己的对象。
A: 由于实现的方式有多种,桥接模式的核心意图就是把这些实现独立出来,让它们各自的变化。这就使得每种实现的变化不会影响其他实现,从而达到应对变化的目的。
5. 桥接模式基本代码
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();
}
}
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();
}
}
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的方法执行");
}
}
B: 桥接模式,就是实现系统可能有多个角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合。
A: 在发现我们需要多角度去分类实现对象,而只是继承会造成大量的类增加,不能满足开放-封闭原则,就应该考虑用桥接模式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。