在开始学习的时候还是要有一个总的轮廓的,大体就是什么是可复用性,可复用性有啥特点,可复用性在哪些方面体现及其具体技术,剩下的就是一些细节了。
1.什么是复用
这里说的复用主要有两个方面的意思:
1.1面向复用编程
也就是说开发出可复用的软件
1.2基于复用编程
利用已有的可复用软件搭建应用系统
这些都很好理解,复用就是用已经有了的代码呗,一方面得使用,一方面还要写适合复用的代码
2.复用的特点
这里我们可以先思考一下,你能复用的东西它一定是存在一些共性的,才能再不同方面被重复使用,因此可复用的程序一定是与抽象程度高,共性强的程序相关联的。
2.1开发复用程序
特点:开发成本高,性能较差,适应性高。
2.2使用复用程序
特点:需要适配,代价可高可低,看适配程度
2.3总的来说
如果割裂开发与使用的话,没法得出客观的结论,但是如果放在一起考虑,我们就知道虽然前期进行复用程序的开发会导致开发成本高,时间多,但是随着开发的继续,可复用程序带来很多便利,比如标准化,高准确性,复用后时间成本降低等诸多特点,下面的图有很好的说明。
这里也可以看出如何衡量开发复用程序的好坏,那就是复用是否频繁,复用代价高低。这里可以简单的说,一个被频繁复用,且复用代价较低的程序,有较好的复用性。
3.四种复用级别
分别是代码(code),模块(class,interface),库(API,.jar),框架(framework)
这里也分两种复用
白盒复用:源代码可见,可修改和扩展,这个用得很多,比如你参考dl的代码进行修改,这就是白盒复用。
黑盒复用:源代码不可见,不能修改,只能使用某个API接口的功能。
3.1code reuse
这各方面大家用的最多就是复制别人的代码,然后简单修改一下来达到自己的功能。这是最低级的复用。
3.2module reuse
这里是重点,下面将介绍的是LSP原则,以及继承和委派来设计复用类
3.2.1LSP原则
1)子类型可以增加方法,但不可删
2)子类型需要实现抽象类型 (接口、抽象类)中所有未实现的方法
3)子类型中重写的方法必须有相同或子类型的返回值或者符合co-variant(协变)的参数
4)子类型中重写的方法必须使用同样类型的参数或者符合contra-variant(逆变)的参数(此种情况Java目前按照重载overload处理)
5)子类型中重写的方法不能抛出额外的异常(协变)
总结:更强的不变量,更弱的前置条件,更强的后置条件
3.2.2协变与逆变
协变:父类型到子类型,越来越具体的spec,返回值类型不变或者更具体,异常类型不变或者减少
逆变:父类型到子类型,越来越具体的spec,参数类型:不变或更抽象。
java不支持逆变,参数不用都看作是overload,想要重写必须是相同的参数类型
3.2.3泛型中的LSP
这里只需要知道结论,泛型不支持LSP也就是说List<Integer>不是List<Number>的子类,原因在于运行时类型擦除,提供为原始类型(父类或Object)
因此使用通配符解决泛型不协变的问题,例如下面这个例子:
本意是要打印任意类型的List,但是由于泛型不协变,不同类型的List不存在父类子类的关系,因此需要使用通配符
这样就可以打印出不同类型的List数组了
这里有特殊的通配符
(1)下限通配符
<? super A> 只能是A的父类或者A
(2)上线通配符
<? extends A> 只能是A(类或接口)的子类或者A
(3)多个限定(类或者接口)
要把类放在前面
3.2.4委派和组合(Delegation and Composition)
这里先给出一个比较的例子来看一下继承和委派的区别。
Comparator接口,用来构造一个比较器,然后用在sort函数中进行比较,使用的是委派
Comparable接口,类继承之后需要实现一个compareTo()的方法,然后override该方法,用在后面的比较,这里类似继承
这两种方法区别就是一个是在类的内部实现的,一个是在外部实现然后委派。
这里也能看出委派和继承的区别:稳定的复用使用继承,灵活的复用使用委派
3.2.4.1委派概念
一个对象请求另一个对象的功能,其实大家用的很多,不要被定义给吓到,就像是大家经常在代码中使用了一个List数组,这就是委派。
3.2.4.2继承和委派
很多设计模式将继承和委派结合使用。
如果子类只需要复用父类中的一部分方法,就是用委派。
如果子类与父类的关系很密切,方法使用很多,就用继承。
继承属于class层面的问题,是类的特点。而委派属于object层面的问题,是对象的特点。
有一个计算不同员工薪水的例子:
其思想就在于薪水的计算与对象密切相关,如果是继承的话重写的可能性极大,因此使用委派会更加灵活。
上面的例子既有继承又有委派,我们称之为组合(composite)
组合优于继承,是委派的一种形式,实现基础就是子类型多态。在后面的设计模式中的策略模式就是借助这种组合的形式。在之后的设计模式中还会讲解,这里只需要知道此时的委派是下面种类中的Dependency临时性的委派,通过参数传递,使用后就消失
大致的设计方式:
3.2.4.3委派的种类
(1)Dependency(A use B)
只在方法的参数或者在方法的局部中使用发生联系,不表示,只使用,每次都要传参
(2)Association (A has B)
表示,可以构造,不可变化,反复使用
(3)Composition (A owns B)
表示时初始化或者唯一构造,客户端不可多种构造,不可变化,可反复使用
(4)Aggregation(更弱的association,可动态变化)
表示,可构造,可变化(set),反复使用
3.3Library reuse
3.3.1Library
一系列的类和方法(API)提供可复用的功能
就是开发者使用存在的库来进行开发,其中常见的就像JDKjava标准库
3.4System level
白盒框架:使用继承
黑盒框架:使用委派
白盒主要是继承框架然后重写方法,黑盒框架是把使用者的代码通过接口传给到框架。
4.总结
这里主要分享了一下什么复用,复用的特点,复用的4个层次。
其中着重说了LSP原则,以及继承与委派。