合成复用原则由成为组合/聚合复用原则,尽量使用对象组合,而不是继承来达到复用的目的
合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。简言之:复用时要尽量使用组合/聚合关系(关联关系),少用继承。
在面向对象设计中,可以通过两种方法在不同的环境中复用已有的设计和实现,即通过组合、聚合关系或者通过继承,但首先应该考虑组合/聚合,组合/聚合可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少;其次才考虑继承,在使用继承时,需要严格遵守里氏替换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及复杂度,因此需要慎重使用继承复用。
通过继承来进行复用的主要问题在于继承复用会破坏系统的封装性,以为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,所以这种复用又称“白箱”复用,如果基类发生改变,那么子类的实现也不得不改变,从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性,而且继承只能在有限的环境中使用。
下面我们举一个例子来对合成复用原则理解:
1 public class A 2 { 3 public void Method1() 4 { 5 Console.WriteLine("我是方法一"); 6 } 7 public void Method2() 8 { 9 Console.WriteLine("我是方法二"); 10 } 11 } 12 13 public class B : A 14 { 15 16 }
类A有2个方法,类B刚好需要调用这两个方法,我们第一可能会想到直接继承,这样“多快好省“,但随着业务进展,功能越来越复杂,A类需要增加其他方法,比如Method3 ,与B类毫无关联,将会大大增加耦合性,合用复用原则的核心就是使用关联,我们可以通过依赖、聚合、合成等关联方法,降低耦合,提高可维护性和降低维护成本。
1 public class A 2 { 3 public void Method1() 4 { 5 Console.WriteLine("我是方法一"); 6 } 7 public void Method2() 8 { 9 Console.WriteLine("我是方法二"); 10 } 11 } 12 13 //依赖 14 public class B 15 { 16 public void Mthod1(A a) 17 { 18 Console.WriteLine("调用A方法"); 19 } 20 } 21 22 //聚合 23 public class C 24 { 25 private A a; 26 27 public void SetA(A al) 28 { 29 a = al; 30 } 31 } 32 33 //合成 34 public class D 35 { 36 public A a = new A(); 37 38 }