HIT-SC-Chapter Nine

HIT-SC-Chapter Nine

9 Construction for Reuse

1 What is Software Reuse?

image-20220609233823632

  • Why ?
    • 降低成本和开发时间
    • 经过充分测试,可靠、稳定
    • 标准化,在不同应用中保持一致
  • cost
    • 应以明确定义、开放的方式设计和构建可重用组件,使用简洁的接口规范、可理解的文档,并着眼于未来的使用。
    • 它涉及到组织、技术和过程变更,以及支持这些变更的工具成本,以及培训人员使用新工具和变更的成本。
  • Development with reuse: 使用已有软件进行开发
    • Reusable Libraries and APIs in JDK
    • Rich third-party libraries and APIs in Java
    • Rich RubyGems

2 How to measure “reusability”?

  • 资产使用的机会越多,其可重用性就越高。
    • Write once, reuse multiple times.
  • Cost
    • 搜索、获取
    • 适配、扩展
    • 实例化
    • 与软件其他部分的互连的难度
  • 可重用性意味着对构建、打包、分发、安装、配置、部署、维护和升级问题的一些显式管理。
  • image-20220609234820758

3 Levels and morphology of reusable components

  • 可重用组件可以是代码
    • 最普遍的:大多数程序员与重用的关系
  • But benefits result from a broader and higher-level view of what can be reused.
    • 但软件构造过程中的任何实体都可能被复用
  • image-20220609234922893
  • What we concern in this lecture
    • Source code level: methods, statements, etc
    • Module level: class and interface
    • Library level: API– Java Library, .jar
    • Architecture level: framework 框架

Types of Code Reuse

  • White box reuse 白盒复用:源代码可见,可修改和扩展
  • 当代码本身可用时,重用代码。通常需要某种修改或适应
    • 复制已有代码到正在开发的系统,进行修改
  • 您可以定制模块以适应特定的情况,这允许在更多的情况下重用
    • 可定制化程度高
  • 现在您拥有定制的结果,因此它增加了代码的复杂性。你需要组件内部的内在知识
    • 对其修改增加了软件的复杂度,且需要对其内部充分的了解
  • Black box reuse 黑盒复用:源代码不可见,不能修改
    • 只能通过API接口来使用,无法修改代码
      • 简单,清晰
      • 适应性差些

Formats for reusable component distribution

  • Source code
  • Package such as .jar, .gem, .dll,
  • 来源:
    • image-20220609235253977

(1) Source code reuse

  • 代码重用——最低级别
    • Copy/paste parts/all into your program
  • 维护问题
    • Need to correct code in multiple places
    • Too much code to work with (lots of versions)
  • High risk of error during process
  • May require knowledge about how the used software works
  • Requires access to source code
  • Example code search: grepcode.com
    • image-20220609235444749
    • github
    • image-20220609235459411
    • Searchcode: searchcode.com
    • image-20220609235516858

(2) Module-level reuse: class/interface

  • Reusing classes
    • 类是代码重用的原子单位
    • Source code not necessary, class file or jar/zip
    • Just need to include in the classpath
    • Can use javap tool to get a class’s public method headers
  • for reuse
    • Documentation very important (Java API)
    • Encapsulation helps reuse 封装有助于重用
    • Less code to manage
  • Versioning, backwards-compatibility still problem版本控制、向后兼容性仍然存在问题
  • need to package related classes together -- Static Linking–需要将相关类打包在一起

Approaches of reusing a class重用类的方法: inheritance继承

  • 扩展了现有类的属性/行为
  • In addition, they might override existing behavior
  • Usually need to design inheritance hierarchy before implementation 通常需要在实现之前设计继承层次结构
  • Cannot cancel out properties or methods, so must be careful not to overdo it 无法取消属性或方法,因此必须小心不要过度

Approaches of reusing a class: delegation委托

  • 委托:将一个实体的任务委派给另一个实体。
    • 例如:Sorter正在将功能委托给某个Comparator
  • Judicious delegation enables code reuse 明智的委托支持代码重用
  • Explicit delegation明确授权:
    • passing the sending object to the receiving object 将发送对象传递给接收对象
  • Implicit delegation隐式委托:
  • by the member lookup rules of the language 根据语言规则的成员查找
  • 委托可以描述为在实体之间共享代码和数据的低级机制

(3) Library-level reuse: API/Package

  • Library: A set of classes and methods (APIs) that provide reusable functionality
  • image-20220610002351529

  • Framework: Reusable skeleton code that can be customized into an application
  • Framework calls back into client code
  • The Hollywood principle: “Don’t call us. We’ll call you.”
  • image-20220610002448042
  • image-20220610002513563
  • Characteristics of a good API
  • image-20220610002537643
  • example:
    • Guava: Google core libraries for Java
    • Apache Commons

(4) System-level reuse: Framework

  • Frameworks are sub-system design containing a collection of abstract and concrete classes along with interfaces between each class 框架:一组具体类、抽象类、及其之间的连接关系
    • 只有“骨架”,没有“血肉”
  • 开发者根据framework的规约,填充自己的代码进去,形成完整系统
    • image-20220610003024891
  • 将framework看作是更大规模的API复用,除了提供可复用的API,还将这些模块之间的关系都确定下来,形成了整体应用的领域复用
  • image-20220610003103611

Framework Design

  • Frameworks differ from applications
    • 抽象级别是不同的,因为框架为一系列相关问题提供了解决方案,而不是单个问题。
    • 为了适应这一系列问题,该框架是不完整的,包含了热点和挂钩,以允许定制
  • 框架可以根据用于扩展它们的技术进行分类
  • Whitebox frameworks白盒框架,通过代码层面的继承进行框架扩展
    • Extensibility achieved through inheritance and dynamic binding.
    • Existing functionality is extended by subclassing framework base classes and
      overriding predefined hook methods现有功能通过对框架基类进行子类化和重写预
      定义的钩子方法来扩展
    • Often design patterns such as the template method pattern are used to override the hook methods. 通常,诸如模板方法模式之类的设计模式用于覆盖钩子方法
  • Blackbox frameworks黑盒框架,通过实现特定接口/delegation进行框架扩展
  • Extensibility achieved by defining interfaces for components that can be plugged
    into the framework. 通过为可插入框架的组件定义接口来实现可扩展性
  • Existing functionality is reused by defining components that conform to a particular
    interface通过定义符合特定接口的组件来重用现有功能
  • These components are integrated with the framework via delegation.这些组件通过
    委派与框架集成

5 Designing reusable classes

(1) Behavioral subtyping and Liskov Substitution Principle (LSP)

Behavioral subtyping

  • Subtype polymorphism: Different kinds of objects can be treated uniformly by client code. 子类型多态:客户端可用统一的方式处理不同类型的对象

    • 如果Cat类型是Animal的子类型,那么Cat类型的表达式可以在任何使用Animal类型表达式的地方使用。
    • image-20220610003609039
  • 子类可以扩展父类的功能,但不能改变父类原有的功能

  • Java中的编译器强制规则(静态类型检查)

    • 子类型可以增加方法,但不可删

    • 子类型需要实现抽象类型中的所有未实现方法

    • 子类型中重写的方法必须有相同或子类型的返回值或者符合co-variance(协变)的参数

    • 子类型中重写的方法必须使用同样类型的参数或者符合contra-variance(反协变)的参数

    • 子类型中重写的方法不能抛出额外的异常

  • Also applies to specified behavior (methods):即Liskov替换原则

    • Same or stronger invariants 更强的不变量
    • Same or weaker preconditions 更弱的前置条件
    • Same or stronger postconditions更强的后置条件
  • Liskov Substitution Principle (LSP)

image-20220610003912496

子类实现相同的不变量

image-20220610004727386

image-20220610004736761

image-20220610004752278

  • 子类实现相同的不变量(子类实现相同的不变量(以及其他不变量))
  • 被重写的方法具有相同的前置和后置条件
  • has weaker precondition has stronger postcondition

Liskov Substitution Principle (LSP)

  • LSP is a particular definition of a subtyping relation, called (strong) behavioral subtyping 强行为子类型化
  • In programming languages, LSP is relied on the following restrictions:
  • image-20220610092149572
  • 参数值:是反协变

Covariance (协变) 关于返回值类型

  • This is called covariance(协变) of return types in the subtype.
  • 父类型→子类型:
    • 越来越具体的specific
    • 返回值类型:不变或变得更具体
    • 异常的类型:也是如此。
  • image-20220610092315427
  • image-20220610092443937
  • 更具体的类可能有更具体的返回类型
  • 为子类型的方法声明的每个异常都应该是为超类型的方法声明的某个异常的子类型
    • 不抛出异常也行

Contravariance (反协变、逆变) 关于参数类型

  • 父类型→子类型:
    • 越来越具体specific
    • 参数类型:要相反的变化,要不变或越来越抽象
  • image-20220610092822577
  • This is actually not allowed in Java, as it would complicate the overloading rules. 目前Java中遇到这种情况,当作overload
    • The method c(Object) of type S must override or implement a supertype method

Summary on subtyping and LSP

image-20220610093015578


Co-variance and Contra-variance

  • Arrays are covariant 协变的
    • 给定Java的子类型规则,T[]类型的数组可能包含T类型的元素或T的任何子类型
    • image-20220610093250596
    • Type of an object vs. Type of a reference 对象类型与引用类型
      • 这里是引用类型

Consider LSP for generics 泛型中的LSP

  • Generics are not covariant.
  • 代码编译完成后,编译器丢弃类型参数的类型信息;因此,此类型信息在运行时不可用。
    • This process is called type erasure类型擦除
  • ArrayList<String> is a subtype of List<String>
  • List<String> is not a subtype of List<Object>
    • image-20220610093553266
    • 我们不能将整数列表视为数字列表的子类型。
    • 这对类型系统来说是不安全的,编译器会立即拒绝它
    • 即Listmethod()不能用来计算List
  • Box不是Box的子类型,即使Integer是Number的子类型。
  • 给定两种具体类型A和B(例如,数字和整数), MyClass与 MyClass没有关
    系,无论A和B是否相关。MyClass
    和MyClass的共同父级是Object

three kinds of Wildcards

  • image-20220610094937103

The unbounded wildcard type(无限定通配符类型)

  • using the wildcard character (?), for example, List<?>.

    • This is called a list of unknown type.
  • 有两种情况下,无限定通配符是一种有用的方法

    • 如果您正在编写一个可以使用Object class中提供的功能实现的方法。
      • 即不使用具体类型的方法
    • 当代码在泛型类中使用不依赖于类型参数的方法时
      • In fact, Class<?> is so often used because most of the methods in
        Class do not depend on T.
  • image-20220610095235509

Lower Bounded Wildcards: <? super A>

  • List List<? super Integer>
    • 前者只匹配整数类型的列表,而后者匹配整数及其超类型的任何类型的列表

Upper Bounded Wildcards: <? extends A>

  • List<? extends Number>

    • image-20220610095437211
    • image-20220610095448638
  • Consider LSP for generics with wildcards

  • image-20220610095556068


(2) Delegation and Composition

image-20220610095753849

  • Interface Comparator
    • 比较它的两个参数的顺序
    • 比较器可以传递给排序方法(例如Collections.sort或Arrays.sort),以允许对排序顺序进行精确控制。比较器还可以用来控制某些数据结构的顺序(如排序集或排序映射),或者为没有自然顺序的对象集合提供顺序。
  • 如果你的ADT需要比较大小,或者要放入Collections或Arrays进行排序,可实现Comparator接口并override compare()函数。
  • image-20220610100114901

Delegation

  • Delegation is simply when one object relies on another object for some
    subset of its functionality (one entity passing something to another entity)
    委派/委托:一个对象请求另一个对象的功能
  • 委派是复用的一种常见形式
  • 委托可以描述为在实体之间共享代码和数据的低级机制
  • Explicit delegation显式: passing the sending object to the receiving object
    将发送对象传递给接收对象
  • Implicit delegation隐式: by the member lookup rules of the language根据
    语言成员查找规则
  • image-20220610100643328
  • Types of delegation
    • Use使用 (A use B)
    • Association关联 (A has B)
    • Composition/aggregation 组成/聚合 (A owns B)
      • 可以认为Composition/Aggregation是Association的两种具体形态
    • 这种分类是根据委托人和被委托人之间的“耦合度”进行的。
    • 都支持1对多的delegation

(1) Dependency: 临时性的delegation

  • 依赖关系:一个对象需要其他对象(供应商)来实现的临时关系
    • 依赖关系的定义为:对于两个相对独立的对象,当一个对象负责构造
      另一个对象的实例,或者依赖另一个对象的服务时,这两个对象之间
      主要体现为依赖关系。
    • The simplest form of using classes is calling its methods; 调用方法
    • 类A当中使用了类B,其中类B是作为类A的方法参数、方法中的局部
      变量、或者静态方法调用。
  • 一个类使用另一个类,但实际上没有将其合并为属性-
    • 它可以是参数,也可以在方法中局部使用。
    • image-20220610102328454
    • image-20220610102510995

(2) Association: 永久性的delegation

  • 对象类之间的持久关系,允许一个对象实例使另一个对象实例代表其执行操作

    • 一个类将另一个类作为属性/实例变量
    • 这种关系是结构化的,因为它指定一种类型的对象与另一种类型的对象相连接,而不表示行为。
    • 对于两个相对独立的对象,当一个对象的实例与另一个对象的一些特定实
      例存在固定的对应关系时,这两个对象之间为关联关系。
  • 关联关系分为单向关联和双向关联

    • 在java中,单向关联表现为:类A当中使用了类B,其中类B是作为类A的成员变量
    • 双向关联表现为:类A当中使用了类B作为成员变量;同时类B中也使用了类A作为成员变量。
    • image-20220610102757347
  • image-20220610102700319

    image-20220610102816757


(3) Composition: 更强的association,但难以变化

  • is a way to combine simple objects or data types into more complex ones.

  • is_part_of: one class has another as a property/instance variable

  • 实现为一个对象包含另一个对象。

  • 组合是一种耦合度更强的关联关系。

  • 存在组合关系的类表示“整体-部分”的关联关系,“整体”负责“部分”的生命周期,他们之间是共生共死的;

  • 并且“部分”单独存在时没有任何意义。

  • image-20220610102921118

    image-20220610103034486

    • People与Soul、Body之间是组合关系,当人的生命周期开始时,必须同时有灵魂和肉体;当人的生命周期结束时,灵魂肉体随之消亡;无论是灵魂还是肉体,都不能单独存在,他们必须作为人的组成部分存在

(4) Aggregation: 更弱的association,可动态变化

  • 对象存在于另一个对象之外,是在外部创建的,因此它作为参数传递给构造函数。
    – has_a

    • 聚合关系是关联关系的一种,耦合度强于关联,他们的代码表现是相同的,仅仅是在语义上有所区别
    • 关联关系的对象间是相互独立的,而聚合关系的对象之间存在着包容关系,他们之间是“整体-个体”的相互关系
  • image-20220610103211950

    image-20220610103258285


  • Delegation vs. Inheritance
    • Inheritance: Extending a Base class by a new operation or overwriting an operation.
    • Delegation: Catching an operation and sending it to another object.
    • “委托”发生在object层面,而“继承”发生在class层面
  • Replace Inheritance with Delegation
    • 如果子类只需要复用父类中的一小部分方法
    • 可以不需要使用继承,而是通过委派机制来实现
    • 本质上,这种重构将两个类分开,并使超类成为子类的助手,而不是其父类。
    • 个类不需要继承另一个类的全部方法,通过委托机制调用部分方法
    • 从而避免大量无用的方法
    • image-20220610100921248

Composite over inheritance principle

  • Or called Composite Reuse Principle (CRP)合成复用原则

  • 类应该通过组合(通过包含实现所需功能的其他类的实例)而不是从基类或父类继承来实现多态行为和代码重用。

  • 尽量使用对象组合,而不是继承来达到复用的目的。合成复用原则就是在一个新的
    对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为
    新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。

  • 简言之

    • 复用时要尽量使用组合/聚合关系(关联关系),少用继承
  • It is better to compose what an object can do (has_a or use_a) than extend what it
    is

    • (is_a).与继承(is_a)相比,更好的方法是组合has_a或use_a)
  • image-20220610101122161

    image-20220610101140730

    • 核心问题:每个Employee对象的奖金计算方法都不同,在object层面而非class层面。

    image-20220610101240772

    image-20220610101251226

    image-20220610101322344


Composite over inheritance principle 更普适的

image-20220610101418644

  • 直接面向具体类型动物的编程:类缺陷:存在大量的重复;不易变化

image-20220610101450604

  • 通过inheritance实现对某些通用行为的复用
  • 缺点:
    • 需要针对“飞法”设计复杂的继承关系树;
    • 不能同时支持针对“叫法”的继承;
    • 动物行为发生变化时,继承树要随之变化。

image-20220610101551433

image-20220610101727964

image-20220610101736817

  • 从组合接口中派生具体类
  • 对接口编程

6 Designing system-level reusable API libraries and Frameworks

Libraries

  • Library: A set of classes and methods (APIs) that provide reusable functionality

    • image-20220610103520732
  • API是程序员最重要的资产和“荣耀”,吸引外部用户,提高声誉


Whitebox and Blackbox frameworks

  • 白盒框架
    • ——通过子类化和重写方法进行扩展
    • ——通用设计模式:模板方法
    • ——子类有主方法,但将控制权交给框架
  • Blackbox框架
    • ——通过实现插件接口进行扩展
    • ——通用设计模式:策略、观察者
    • ——插件加载机制加载插件,并将控制权交给框架

image-20220610103714501

image-20220610103728171

image-20220610103800085

  • 子类有主方法,但给框架控制

image-20220610103838877

image-20220610103918052

  • 插件加载机制加载插件,并将控制权交给框架

image-20220610104007077

image-20220610104017537

image-20220610104027663

Whitebox vs. Blackbox Frameworks

  • Whitebox frameworks use subclassing/subtyping ---继承
    • 允许扩展每一个非私有的方法-
    • 需要理解超类的实现-
    • 一次只有一个扩展-
    • 一起编译-通常被称为开发框架
  • Blackbox frameworks use composition --委派/组合
    • -允许扩展暴露在界面中的功能
    • -只需要了解界面
    • -多个插件
    • -通常提供更多的模块
    • -独立部署可能(.jar, .dll,…)
    • -通常所谓的终端用户框架,平台

image-20220610104214976


SUM

image-20220610104229210

image-20220610104242083

posted @ 2022-06-03 09:28  三金同志  阅读(57)  评论(0)    收藏  举报