1. 紧耦合的程序演化

代码结构图:
图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,岂不是更炸。

另一个结构图:
图2
B: 这样子,要是增加手机功能或品牌都会产生很大的影响。
A: 很多情况下,用继承会带来麻烦。比如,对象的继承关系是在编译时就定义好了,所有无法在运行时改变从父类继承的实现。子类实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要的复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。
A: 在面向对象设计中,我们还有一个很重要的设计原则,那就是合成/集合复用原则。即优先使用对象合成/复用,而不是类的继承。

2. 合成/集合原则

尽量使用合成/集合,尽量不要使用类继承。

集合表示一种弱的'拥有'关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;合成则是一种强的'拥有'关系,体现了严格的部分和整体关系,部分和整体的生命周期一样。
好处是,优先使用对象的合成/集合将有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小的规模,并且不太可能增长不可控制的庞然大物。

B: 像游戏,通讯录等这些功能都是软件,如果我们可以让其分离与手机的耦合,那么就可以大大减少面对新需求时改动过大的不合理情况。
A: 手机品牌和手机软件之间的关系呢?
B: 手机品牌包含手机软件,但软件并不是品牌额一部分,所有它们之间是耦合关系。
图3

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: 由于实现的方式有多种,桥接模式的核心意图就是把这些实现独立出来,让它们各自的变化。这就使得每种实现的变化不会影响其他实现,从而达到应对变化的目的。
图1
图3
图3

5. 桥接模式基本代码

图7

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: 在发现我们需要多角度去分类实现对象,而只是继承会造成大量的类增加,不能满足开放-封闭原则,就应该考虑用桥接模式。


yuanoung
10 声望1 粉丝

« 上一篇
单例模式
下一篇 »
命令模式

引用和评论

0 条评论