面向对象设计原则三

来源:互联网 发布:乐视mac码怎么查 编辑:程序博客网 时间:2024/05/02 01:37

  面向对象设计的重要原则是创建抽象化,并且从抽象化导出具体化,具体化给出不同的实现。继承关系就是一种从抽象化到具体化的导出。[Page]
  抽象层包含的应该是应用系统的商务逻辑和宏观的、对整个系统来说重要的战略性决定,是必然性的体现。具体层次含有的是一些次要的与实现有关的算法和逻辑,以及战术性的决定,带有相当大的偶然性选择。具体层次的代码是经常变动的,不能避免出现错误。
  从复用的角度来说,高层次的模块是应当复用的,而且是复用的重点,因为它含有一个应用系统最重要的宏观商务逻辑,是较为稳定的。而在传统的过程性设计中,复用则侧重于具体层次模块的复用。
  依赖倒转原则则是对传统的过程性设计方法的“倒转”,是高层次模块复用及其可维护性的有效规范。
  特例:对象的创建过程是违背“开—闭”原则以及依赖倒转原则的,但通过工厂模式,能很好地解决对象创建过程中的依赖倒转问题。
  3.2关系
  “开-闭”原则与依赖倒转原则是目标和手段的关系。如果说开闭原则是目标,依赖倒转原则是到达/"开闭/"原则的手段。如果要达到最好的/"开闭/"原则,就要尽量的遵守依赖倒转原则,依赖倒转原则是对/"抽象化/"的最好规范。
  里氏代换原则是依赖倒转原则的基础,依赖倒转原则是里氏代换原则的重要补充。
  3.3耦合(或者依赖)关系的种类:
  零耦合(Nil Coupling)关系:两个类没有耦合关系
  具体耦合(Concrete Coupling)关系:发生在两个具体的(可实例化的)类之间,经由一个类对另一个具体类的直接引用造成。
  抽象耦合(Abstract Coupling)关系:发生在一个具体类和一个抽象类(或接口)之间,使两个必须发生关系的类之间存有最大的灵活性。
  3.3.1如何把握耦合
  我们应该尽可能的避免实现继承,原因如下:
  1 失去灵活性,使用具体类会给底层的修改带来麻烦。
  2耦合问题,耦合是指两个实体相互依赖于对方的一个量度。程序员每天都在(有意识地或者无意识地)做出影响耦合的决定:类耦合、API耦合、应用程序耦合等等。在一个用扩展的继承实现系统中,派生类是非常紧密的与基类耦合,而且这种紧密的连接可能是被不期望的。如B extends A,当B不全用A中的所有methods时,这时候,B调用的方法可能会产生错误!
  我们必须客观的评价耦合度,系统之间不可能总是松耦合的,那样肯定什么也做不了。
  3.3.2我们决定耦合的程度的依据何在呢?
  简单的说,就是根据需求的稳定性,来决定耦合的程度。对于稳定性高的需求,不容易发生变化的需求,我们完全可以把各类设计成紧耦合的(我们虽然讨论类之间的耦合度,但其实功能块、模块、包之间的耦合度也是一样的),因为这样可以提高效率,而且我们还可以使用一些更好的技术来提高效率或简化代码,例如c#中的内部类技术。可是,如果需求极有可能变化,我们就需要充分的考虑类之间的耦合问题,我们可以想出各种各样的办法来降低耦合程度,但是归纳起来,不外乎增加抽象的层次来隔离不同的类,这个抽象层次可以是抽象的类、具体的类,也可以是接口,或是一组的类。我们可以用一句话来概括降低耦合度的思想:/"针对接口编程,而不是针对实现编程。
  在我们进行编码的时候,都会留下我们的指纹,如public的多少,代码的格式等等。我们可以耦合度量评估重新构建代码的风险。因为重新构建实际上是维护编码的一种形式,维护中遇到的那些麻烦事在重新构建时同样会遇到。我们知道在重新构建之后,最常见的随机bug大部分都是不当耦合造成的 。[Page]
  如果不稳定因素越大,它的耦合度也就越大。
  某类的不稳定因素=依赖的类个数/被依赖的类个数
  依赖的类个数= 在编译此类的时被编译的其它类的个数总和
  3.3.3怎样将大系统拆分成小系统
  解决这个问题的一个思路是将许多类集合成一个更高层次的单位,形成一个高内聚、低耦合的类的集合,这是我们设计过程中应该着重考虑的问题!
  耦合的目标是维护依赖的单向性,有时我们也会需要使用坏的耦合。在这种情况下,应当小心记录下原因,以帮助日后该代码的用户了解使用耦合真正的原因。
  3.4怎样做到依赖倒转?
  以抽象方式耦合是依赖倒转原则的关键。抽象耦合关系总要涉及具体类从抽象类继承,并且需要保证在任何引用到基类的地方都可以改换成其子类,因此,里氏代换原则是依赖倒转原则的基础。
  在抽象层次上的耦合虽然有灵活性,但也带来了额外的复杂性,如果一个具体类发生变化的可能性非常小,那么抽象耦合能发挥的好处便十分有限,这时可以用具体耦合反而会更好。
  层次化:所有结构良好的面向对象构架都具有清晰的层次定义,每个层次通过一个定义良好的、受控的接口向外提供一组内聚的服务。
  依赖于抽象:建议不依赖于具体类,即程序中所有的依赖关系都应该终止于抽象类或者接口。尽量做到:
  1、任何变量都不应该持有一个指向具体类的指针或者引用。
  2、任何类都不应该从具体类派生。
  3、任何方法都不应该覆写它的任何基类中的已经实现的方法。
  3.5依赖倒转原则的优缺点
  依赖倒转原则虽然很强大,但却最不容易实现。因为依赖倒转的缘故,对象的创建很可能要使用对象工厂,以避免对具体类的直接引用,此原则的使用可能还会导致产生大量的类,对不熟悉面向对象技术的工程师来说,维护这样的系统需要较好地理解面向对象设计。
  依赖倒转原则假定所有的具体类都是会变化的,这也不总是正确。有一些具体类可能是相当稳定,不会变化的,使用这个具体类实例的应用完全可以依赖于这个具体类型,而不必为此创建一个抽象类型。
  四、合成/聚合复用原则(Composite/Aggregate Reuse Principle或CARP)
   4.1概念
  定义:在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用这些对象的目的。
  应首先使用合成/聚合,合成/聚合则使系统灵活,其次才考虑继承,达到复用的目的。而使用继承时,要严格遵循里氏代换原则。有效地使用继承会有助于对问题的理解,降低复杂度,而滥用继承会增加系统构建、维护时的难度及系统的复杂度。
  如果两个类是“Has-a”关系应使用合成、聚合,如果是“Is-a”关系可使用继承。/"Is-A/"是严格的分类学意义上定义,意思是一个类是另一个类的/"一种/"。而/"Has-A/"则不同,它表示某一个角色具有某一项责任。

原创粉丝点击