在设计模式的六原则中提到“合成/聚合”原则,其核心思想是尽量使用合成/聚合,尽量不要使用类继承。那么,问题来了,为什么在编程中尽量不要使用类继承呢?举个例子我想大家就能明白了。
现在,手机已经成为我们普遍使用的的通讯工具。手机分为很多很多的品牌,如:“三星、华为、苹果”等。另外,手机除了通讯功能外,还添加了许多的娱乐功能。应用面向对象的思想,将上述内容中用UML类图表示出来,结果如下:
从图中可以看出,类与类之间的关系全部用继承实现,手机作为一个父类,手机N和手机M作为子类继承与手机类,通讯类和游戏类作为子类继承它们的父类。这样的关系,我们在代码中很容易实现。但是,当我们的需求改变,要在通讯类中添加一个方法,这时就需要我们队通讯类的父类(手机N)做修改,当然在手机N的父类(手机)也要做修改,这极大地违背了“开放/封闭”原则。
"合成/聚合"原则的核心思想是用组合、聚合关系代替继承关系,这个原则在桥接模式中有很好的体现。桥接模式的定义是将抽象部分与它的的实现部分分离,使它们都可以独立地变化。在上述例子中,抽象类是手机品牌,其子类有手机N和手机M,通讯类和游戏类继承与手机类,而单独封装起来做为实现类用于实现手机的功能。现在详细地介绍一下桥接模式的实现。
桥接模式的结构图
桥接模式的代码实现
抽象类(手机品牌类)
abstract class HandsetBrand //手机类,相当于抽象类。
{
protected HandsetSoft soft;
public void SetHandsetSoft(HandsetSoft soft)
{
this.soft = soft;
}
public abstract void Run();
}
class HandsetBrandN : HandsetBrand//手机N
{
public override void Run() //实现父类的方法
{
soft.Run();
}
}
class HandsetBrandM:HandsetBrand //手机M
{
public override void Run()
{
soft.Run();
}
}
手机软件类作为实现类,其子类为通讯类和游戏类。
abstract class HandsetSoft //手机软件类,等同于实现类
{
public abstract void Run(); //抽象方法
}
class HandetGame : HandsetSoft
{
public override void Run()
{
Console.WriteLine("运行手机游戏");
}
}
class HandsetAddressList : HandsetSoft
{
public override void Run()
{
Console.WriteLine("运行手机通讯录");
}
}
客户端代码
class Program
{
static void Main(string[] args)
{
HandsetBrand ab; //定义变量ab ,其类型为HandsetBrand
ab = new HandsetBrandN(); //实例化HandserBranN的对象,将其赋值与ab
ab.SetHandsetSoft(new HandetGame()); //将手机游戏作为参数传递给SetHandsetSoft方法
ab.Run(); //运行
ab.SetHandsetSoft(new HandsetAddressList());
ab.Run();
}
}
运行结果为
总结:
当我们在编程过程中需要有多层继承关系的类时,要尽可能地去用聚合/组合关系。桥接模式就是很好的体现,把多层具有继承关系的类分成抽象类和实现类,达到解耦的目的,从而使抽象类和实现类可以独立变化,不影响彼此。