HIT软件构造 blog6

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

博客5写的有点太长了,但是其实复习才刚刚开始,需要记录的太多了,这里从OOP的复习开始,继续记录吧!


一、OOP 复习

1.1 接口 interface

类与接口:
接口之间可以继承与扩展
一个类可以实现多个接口
一个接口也可以有多种实现类

接口的样子:
在这里插入图片描述
可以看到接口不具备构造函数,所以调用实现类的构造函数(一个接口是有很多个实现类的),比如:
在这里插入图片描述
但是其实观察到,这里需要调用一个实现类,这样就其实是把某个具体实现的实现类给暴露出来了,用户端就知道了我们的一个类,这样当然不行!比如下面这样:
在这里插入图片描述
这里我们就需要用后面要学的静态工厂方法了,我们可以在接口的静态方法中将这个实现类的构造函数进行封装,这样就看不到了。客户端需要构造一个新的对象直接用构造方法就行了。
在这里插入图片描述

1.2 接口中的default方法

default方法可以在接口中直接写出它的实现,在实现类中就不用再写这个实现了,多个实现类都可以使用这个接口中的方法。

接口中的static方法也再接口中写出,不需要在实现类中再写,调用创建时可以直接调到接口中的方法·

1.3 interface的应用与书写的例子

  1. 首先interface的第一个方法不能是构造方法,接口不能有接口方法,可以用静态方法
  2. 接口中第二个方法在实现类中没有进行重写,接口中的每个都必须要被实现!不过你可以新添加方法
  3. union方法不能返回一个arrayset方法,这出现了表示泄露
  4. add方法是Mutator这不符合这个类的spec

在这里插入图片描述

1.2 继承的重写

接口是可以继承接口的,也可以是一个接口继承多个接口
注意区分几个术语:
接口与接口之间是扩展关系 :extends
接口实现类是:implements
类与类之间的继承关系:也是extends关键字,不过这个被称为Inheritance

重写是函数名、函数参数类型数量次序、函数返回值都一致
调用子类型的方法还是子类型的方法,在运行时 动态地决定

PS:(特殊情况)

  1. 如果子类中没有重写,那么会直接调用父类的方法
  2. 如果父类中没有写,那么它们之间没有共性,需要子类自行实现
  3. 可以在子类中override的方法中实现特殊的功能,同时调用父类的方法,例子:

在这里插入图片描述

  1. 如果在构造方法中调用super,那么super只能在第一行,如果不是构造函数的第一行那么不会通过静态检查

1.2 抽象类

形容词abstract
在class前面加上abstract意味着是抽象类,但是至少有一个方法是abstract的
抽象的类意味着这个类在客户端不能被直接实例化的
和接口是一样的,它的实现需要先实现子类,然而在子类中我们需要将抽象方法实现

1.3 多态 、子类型、重载

1.3.1 三种多态

  • 功能重载
  • 泛型
  • 子类型多态 (最重要!!)

1.3.2 重载

参数列表类型不同或者返回值不同,在静态检查的时候进行参数匹配的时候,在编译阶段就决定了要执行哪个方法

  • 必须要求参数列表类型不同
  • 返回值类型、public等修饰、异常都是可以相同可以不同的
  • 可以在同一个类中进行重载也可以在不同的类进行重载

例子分析:
1、2、3都是重载,第四个需要参数类型不同!只改变它的参数名是没有用的
第五个只改变了返回值类型,没有改变参数列表,也不选
在这里插入图片描述
例子分析:
重载用需要的是静态类型检查,只看运行之前等号前面的类型,因为这时候他还没有被赋值
在这里插入图片描述
对比总结:
在这里插入图片描述

1.4 重写equals方法

这部分在我的blog3中已经有所体现,不过这里需要补充的三点:

  1. 任何对象equals(null)都返回false
  2. 作为重写方法,equals的参数应该是object,不能被改变
  3. Mutable的类可能实现的是观察等价性也有可能是行为等价性,常用的要注意Date和List都是行为等价性,例题如下:
    在这里插入图片描述

二、可复用性的度量、形态与外部表现

  • 源代码级别的复用
  • 模块级别的复用:类/抽象类/接口
  • 库级别的复用:API/包
  • 系统级别的复用:框架 framework

如何评估是否适合复用:

  • 小、简单——》复用范围大
  • 与标准兼容
  • 灵活可变
  • 可扩展
  • 泛型,参数化
  • 模块化
  • 变化的局部性——>表示独立性,不要让只改变一个模块,很多地方需要改动
  • 稳定
  • 丰富的文档和帮助

复用力度:
在这里插入图片描述

三、子类型多态

子类型多态:客户端可用统一的方式处理不同类型的对象
用子类型可以无条件地取代任何一个父类型

LSP原则

  1. 子类型可以增加方法,但不能删除
  2. 子类型需要实现抽象类型中的所有未实现方法
  3. 子类型中重写的方法必须有相同或者子类型的返回值或者符合co-variance的参数 (协变)
  4. 子类型中重写的方法必须使用同样的参数或者符合contra-variance (逆变) 的参数
  5. 子类型中重写的方法不能抛出额外的异常,满足协变
  6. 更强的不变量
  7. 更弱的前置条件
  8. 更强的后置条件
    PS:父类型和子类型的可变与不可变类型应该一致
    注意这里我们对重写的要求和上面所说的重写需要完全一致不同,这里重新规定了,重写只需要返回值满足协变, 参数满足逆变(JAVA不支持逆变) 以及不抛出额外的异常,满足协变即可。
    也就是说,子类型重写的返回值应该更具体,抛出的异常也应该更具体(类变得具体,返回值和异常也变得具体,这就是协变)

基础类型的协变

可以把子类型的复制给父类型的
在这里插入图片描述
但是如果已经定义赋值为子类型,比如Integers就固定为Integers,就不能再传入一个double的
在这里插入图片描述

泛型的协变

泛型不存在协变关系,因为类型擦除,所以传入的泛型都被看做Object
就像下面的List是ArrayList的父类
但是List不是List的父类,两者已经没有关系了
在这里插入图片描述
因此我们可以看到这里的错误,list已经不是list的子类型了,不能直接赋值,认为将子类型赋值给父类型
在这里插入图片描述
integer是number的子类型,但是放到Box里面因为泛型不存在协变,Box和Box
在这里插入图片描述
但是我们想要利用泛型的协变,这就需要通配符了,而不能用object
在这里插入图片描述
通配符的其他两个用法:
? super A : A 的父类型都可以传入
?extends A : A 的子类型都可以传入

相关题目练习:
在这里插入图片描述
答案:abcd
解析:A很明显,List和List没有关系,并不是List的子类
B和D使用了通配符,需要在方法参数那里用通配符才可以,然后根据通配符的范围传入参数
而C选项,ArrayList 和list的泛型不一致,不存在继承关系

四、delegation 委托

委派/委托:一个对象请求另一个对象的功能
委派是对象与对象之间的关系!! ,在构造函数中,传入了a的对象,建立了delegation
需要注意的是继承则是类与类之间的关系!!!
在这里插入图片描述
继承是比委派更强的关系,在UML中,继承用的是is_a而委派则是has_a或者是use_a
在这里插入图片描述

两种不同类型的delegation

依赖性委托(Dependence):临时性的delegation

只是方法参数传递,而没有属性
在这里插入图片描述

关联关系(Association):永久性性的delegation(包括composition和aggregation)

在属性中就传入了
可以通过参数传入后赋值,也可以没有参数直接在方法中new
在这里插入图片描述

不推荐的composition(组合),更强的Association

这是一种更强的关联关系,在属性中就写固定了,而不是像关联关系一样在构造函数中赋值,在属性中就已经把子类型写了出来,修改时很难修改
在这里插入图片描述

aggregation(聚合),更弱的Association,可以动态变化

通过传入参数
在这里插入图片描述
四个概念的关系:
在这里插入图片描述

五、framework 框架的复用

分为白盒框架和黑盒框架
白盒框架:继承和重写——模板方法
黑盒框架:delegation
两者的关系与不同,黑盒是终端在框架中运行,而白盒实际上因为父类是抽象的类,运行的是子类型
在这里插入图片描述

例子,白盒框架示例:
子类型继承了父类型,子类型重写了方法,在客户端调用时候直接调用了子类型
在这里插入图片描述
黑盒框架:通过关联关系,设置一个外部的对象textToshow,需要进行扩展的方法都在这个外部对象中进行实现,这个外部对象也可以是外部接口,后续可以对这个外部的接口进行实现。
客户端调用的时候只需要传入一个外部对象就行了
在这里插入图片描述

六、Adapter 适配器

复用一个接口不匹配的API
在这里插入图片描述
适配器是实现一个接口得到的,面向接口的编程,具体例子:
在这里插入图片描述

六、Decorator 装饰器

Decorator下面方法是个性的方法
在这里插入图片描述
基础方法,共性功能的例子:
在这里插入图片描述
对此,后面装饰器实现Stack接口的例子,注意,这里的基础功能是直接调用的基础类
在这里插入图片描述
具体的子类,继承StackDecorator,仍然是实现Stack接口,可以添加新的Rep并且实现自己独有的功能
在这里插入图片描述
客户端处的调用:
在这里插入图片描述
例题:
在这里插入图片描述
答案:BD
解析:首先明确的是,其实s是可以传入任何Stack子类型的,不过就是传入Undostack没有必要再进行装饰。A是对的,B是错的。然后是C选项,,运行时当然是secureStack。D选项,这进行了三个new,实际上是有四个Stack存在,修饰之前的和修饰之后的不是一个stack

七、Strategy 策略

要实现多个算法,有A和B两个算法实现。面向接口抽象的接口编程,接口Strategy
客户端在Context处,选择哪一种算法
在这里插入图片描述
客户端调用例子:在这里我们传入的是两个策略子类型(也可以用静态工厂方法隐藏)
在这里插入图片描述
传入后在Context类里面得到子类型参数,可以进行委派,例:
在这里插入图片描述
它的子类型具体实现,重写了接口的方法:
在这里插入图片描述

八、Template Method 模板方法

用于白盒框架,只实现一棵继承树,使用继承和重写实现模板模式,大概的继承关系如下:
在这里插入图片描述
其中要注意的是,templateMethod()方法是公共的,不能修改,所以应该用final修饰,其中#step1 和 #step2 等三个方法是抽象abstract方法,在后续的子类里面进行实现。
例子:
在这里插入图片描述
模板:
在这里插入图片描述
子类重写:
在这里插入图片描述
例题:
在这里插入图片描述
答案:AD
解析:
主要是A选项,它应该是抽象类,如果是接口就都不能实现了(当然题目的意思应该是没考虑default方法和静态方法),我们想要实现公共的方法就需要是abstract类

九、Iterator 迭代器模式

在这里插入图片描述
代码实现:
在这里插入图片描述
想要自己的类Pair类可以实现迭代操作,就需要让他实现Iterable接口,让他具有那个可以返回一个迭代器的方法,iterator。这时候返回的迭代器可以是自己写的迭代器·。而这个PairIterator类是实现iterator接口,实现三个基本方法·。
在这里插入图片描述

十、补充:UML的六种箭头

泛化,多用于继承关系

**表示方法:**用实线空心三角箭头表示,如下图。
在这里插入图片描述

实现 (类与接口的关系)

**表示方法:**空心三角形箭头的虚线,实现类指向接口,如下:
在这里插入图片描述

依赖(临时性的delegation)

依赖性委托(Dependence):临时性的delegation,只是方法参数传递,而没有属性
表示方法: 虚线箭头,类A指向类B,即A依赖B,如下图:
在这里插入图片描述

关联(长期性)

程序中一个类的全局变量引用了另一个类,就表示关联了这个类,关联关系分为单项关联和双向关联。在Java中,单向关联表现为:类A当中使用了类B,其中B作为类A的成员变量。双向关联表现为:类A当中使用了类B作为成员变量;同时类B中也使用了类A作为成员变量。

**表示方法:**实线箭头,类A指向类B,即A关联B,如下图,消费者种关联了若干产品:
在这里插入图片描述

聚合

has-a关系
**表示方法:**尾部为空心菱形的实线箭头(也可以没箭头),车轮和大灯都属于汽车,如下图:
在这里插入图片描述

组合

表示方法: 尾部为实心菱形的实现箭头(也可以没箭头)
在这里插入图片描述

十一、可维护性!!(各种原则)

软件维护:修复错误,改善性能
四种维护:纠错性、适应性(更改环境,要能适应新版本环境)、完善性(对软件性能的增强)、预防性

模块化编程

高内聚,低耦合
分离关注点:多用委派
信息隐藏

评价模块化的几个标准

可分解性
可组合性
可理解性
可持续性——发生变化时收到影响范围最小
出现异常之后的保护——出现异常后受范围的影响小

模块化编程的几个原则

直接映射
尽可能少的接口——耦合度降低
尽可能小的接口——
显式接口
信息隐藏

SOLID原则

SRP 单一责任原则

不应该多于1个原因让你的ADT发生变化,否则就把他们拆开

OCP 开放-封闭原则——可以加新的类,但是不要改写好的类

对扩展的开放
模块应是可扩展的,从而该模块可表现出新的行为以满足需求的变化

对修改的封闭

LSP Liskov替换原则
DIP 依赖转置原则——客户端应该依靠更加抽象的类

具体的模块依赖于抽象的模块
例子:
copy原来依赖于下面两个类,但是因为具体的类容易发生变化,如果具体的类发生变化,Copy也容易跟着动
在依赖翻转后,做一层接口层,进行隔离,面向接口进行编程
从稳定的依赖不稳定的,抽象的依赖具体的
变成抽象的依赖抽象的
在这里插入图片描述

ISP 接口隔离原则

大的接口可分解为多个小的接口
不同的接口向不同的客户端提供服务
客户端只方位你自己所需要的端口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值