设计可复用的类:继承与重写、重载、参数多态与泛型、lsp替换原则、组合与委托
面向复用编程的目的:降低成本与开发时间。
复用:白盒复用、黑盒复用
白盒复用:可见源代码,可修改扩展。复制已有代码至正在开发的系统进行修改,对其
修改增加了软件的复杂度,且需要对其内部充分的了解
白盒框架,通过代码层面的继承进行框架扩 展
黑盒复用:源代码不可见,不可修改。只能通过API接口来使用,无法修改代码 。适应性差些
黑盒框架,通过实现特定接口/delegation进 行框架扩展
继承:
继承是一种复用模式,子类可以复用父类的方法,也可以重写。
委托:委派只是一个对象依赖另一个对象来实现其功能的某个子集。
LSP替换原则:
行为子类:
子类型多态:客户端可用统一的方式处理不同类型的对象
如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T
定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有 发生变化,那么类型S是类型T的子类型。所有引用基类的地方必须能透明地使用其子类的对象。
LSP替换原则:
1.子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法;
2、子类中可以增加自己特有的方法。
子类必须实现父类所有非私有的属性和方法,或子类的所有非私有属性和方 法必须在父类中声明。即,子类可以有自己的“个性”,这也就是说,里氏 代换原则可以正着用,不能反着用(在项目中,采用里氏替换原则时,尽量 避免子类的“个性”,一旦子类有“个性”,这个子类和父类之间的关系就 很难调和了)。根据里氏代换原则,为了保证系统的扩展性,在程序中通常 使用父类来进行定义,如果一个方法只存在子类中,在父类中不提供相应的 声明,则无法在以父类定义的对象中使用该方法。
尽量把父类设计为抽象类或者接口。让子类继承父类或实现父接口,并实现 在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地 扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增 加一个新的子类来实现
子类型可以增加方法,但是不可删除,同时需实现抽象类型中所有的为实现方法。子类型中重写的方法必须使用同样类型的参数,且不可抛出额外的异常。对于规约:前置条件不能强化,后置条件不能弱化,不变量要保持。
继承复用的优缺点:
通常类的复用分为继承复用和合成复用两种,继承复用虽 然有简单和易实现的优点。
继承复用破坏了类的封装性。因为继承会将父类的实现细 节暴露给子类,父类对子类是透明的,所以这种复用又称 为“白箱”复用。
子类与父类的耦合度高。父类的实现的任何改变都会导致 子类的实现发生变化,这不利于类的扩展与维护。
它限制了复用的灵活性。从父类继承而来的实现是静态的 ,在编译时已经定义,所以在运行时不可能发生变化
委派:如果子类型只需复用父类型中的一小部分,可以通过委派机制实现。