设计原则

  • 找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起
  • 针对接口编程,而不是针对实现编程

在面向对象设计方法中有很多值得提倡的方法,这些方法可以为我们的设计带来很大的灵活性,可复用性。其中一个原则就是“针对接口编程,而不是针对实现编程” 这个原则带来的好处有以下几点: Client不必知道其使用对象的具体所属类。 Client无需知道特定类,只需知道他们所期望的接口。 一个对象可以很容易地被(实现了相同接口的)的另一个对象所替换。 对象间的连接不必硬绑定(hardwire)到一个具体类的对象上,因此增加了灵活性。 松散藕合(loosens coupling)。 增加了重用的可能性。提高了(对象)组合的机率,因为被包含对象可以是任何实现了一个指定接口的类。 在实现上: C++通过继承纯虚类来实现接口继承。 Java对接口继承具有单独的语言构造方式-Java接口。

但从辩证法的角度看,事物总有利有弊。“针对接口编程”有如上诸多好处,确不可避免的带来设计的复杂性。特别对于没有丰富经验的设计人员。 其中令我比较困惑的地方是: 要想针对接口编程,就必然要最大化接口类,使包括所有子类的方法,这样我们才能利用多态性用接口类来一致的操作子类。但这会带来以下几点不足。 违反面各对象的另一个原则,这个原则是:一个类只能定义那些对它的子类有意义的操作。 接口类包括了并不是对每一个子类都有意义的方法,使接口类臃肿,难以理解。 从父类继承的无用方法,如何处理。

举个例子来说。我们要实现这样一个功能模块。一个TreeView上有各种节点。我们对这样的一个Tree 的节点操作。比如复制,剪切,粘贴,重命名,查看属性、设置它的图标,添加到树节点上等等。每种节点的相同操作(比如复制)的实现是不同的。 你会怎么设计它: 在C++中我会这样做。 我会将每种结点实现成一个类。以实现各自的相关操作(比如复制,粘贴),这些类都继承至一个纯虚的父类,在这个父类中以虚方法的方式声名子类实现我的相关方法,这样做的好处是当你从Tree中取出一个节点时,你不必关心这个节点是什么类实现的,你只需要以纯虚的父类指针操作它就可以了,这样就实现了接口继承的所带来的优点。 但是,如果并不是每个节点都支持所有的方法,比如有些节点不允许复制,有些节点不允许重命名等,那么从父类继承的声名如何处理,实现成一个空方法么?还是不将这样的方法放到父类中?如果不放到父类中,就没办法以统一的方法操作所有的子类了!