软件构造复习内容(6)---可维护性
1.Modular design 模块化设计
模块化编程想要实现的目标是
- 高内聚 模块之内高内聚
- 低耦合 模块之间低耦合
https://blog.csdn.net/caoxuecheng001/article/details/80231220
这个链接介绍了模块之间的耦合和聚合
模块设计的5个原则
Direct Mapping(直接映射)
Few Interfaces(尽可能少的接口)
Small Interfaces(尽可能小的接口)
Explicit Interfaces(显式接口)
Information Hiding(信息隐藏)
2.OO设计原则
SOLID原则
SRP(The Single Responsibility Principle) 单一责任原则
OCP(The Open-Closed Principle) 开闭原则
LSP(The Liskov Substitution Principle) Liskov替换原则
DIP(The Dependency Inversion Principle) 依赖-转置原则
ISP(The Interface Segregation Principle) 接口聚合原则
SRP:单一责任原则
不应该有有多余一个原因让ADT变化,否则就拆开
一个类,引起一个变化
直观的理解就是一个类负责一个功能
OCP:开闭原则
对扩展性的开放,对修改的封闭
模块的行为应该是可扩展的,从而满足新的需求
但是模块自身的代码不应被修改,以保证原先功能的完好
实现OCP的关键解决方法:抽象技术
比如说要采用数据库,构造一个抽象的AbstractServer,然后具体的Server继承这个类,在使用时用AbstractServer声明数据库,然后进行使用
对其的扩展很方便,新写一个使用其他数据库的类继承AbstractServer即可
LSP:Liskov替换原则
子类型必须能够替换其基类型
派生类必须能够通过其基类的接口使用,客户端无需了解两者之间的差异。
要求父类能实现的功能,子类也必须能够实现。
ISP:接口隔离原则
不能强迫客户端依赖于他们不需要的接口,只提供必须的接口
不要胖接口不要胖接口不要胖接口
胖接口不够聚合
胖接口可以分解为多个小接口
不同的接口向不同的客户端提供服务
客户端只访问自己需要的接口
DIP:依赖转置原则
抽象的模块不应该依赖具体的模块
具体应该依赖抽象
上层的client的代码面向抽象接口编程,隔离对下层具体实现机制的直接接触
即 delegation的时候要通过interface建立联系,而不是具体子类
3.OO设计模式
1.Creational patterns (如何“创建新的实例”)
(1)Factory method pattern 工厂模式
当client不知道要创建那个具体类的实例时,或者不想在client代码中指明要具体创建的实例时,采用工厂方法
定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个类的实例化延迟的其子类
工厂内有一系列返回具体类的方法,客户端只需要调用工厂内的方法即可创建对象,当有新的具体产品类时,在工厂类中加入新的工厂函数(OCP,开闭原则)即可,不影响客户端代码

静态工厂方法
不需要创建工厂的实例,直接使用类名调用的工厂方法,既可以在ADT内部实现,也可以单独构造工厂类
工厂方法很好的遵守了OCP原则
(2)Abstract Factory 抽象工厂方法
提供工厂模式,提供接口已创建一组相关/相互依赖的对象,但不需要指明具体类
比如说,提供一组控件样式(2个按钮,1个文本框)就可以使用抽象工厂方法

抽象工厂方法创建的不是一个完整的产品,而是产品族(遵循固定搭配规则的多类产品的实例),得到的结果是:多个不同的产品的Object,各产品创建过程对client可见,但是“搭配”不变
2.Structural patterns(结构模式)
(1)Proxy 代理模式
某个对象比较“敏感”“私密”“贵重”,不希望被client直接访问到,故设置proxy,在二者之间建立防火墙
client访问代理类,代理类委托真实类完成功能
如果真实类实例化很复杂,可以减少消耗的时间,当真正用到相应的功能时,在委托真实类完成。
3.Behavioral pattterns 表现模式
(1)Observer 观察者模式
参考https://www.cnblogs.com/yssjun/p/11107038.html
发布-订阅模式即多个订阅者(观察者)向发布者(被观察者)订阅状态信息,当发布者更新状态时会将状态信息向它的订阅者发布信息。发布者需要自己维护订阅者列表,可以注册或者注销对状态信息感兴趣或不感兴趣的订阅者。
能够建立对象间一对多的关联关系,并且能使一个对象的变化被关联对象感知

Subject:
抽象被观察者(发布方),提供注册(Attach)和删除(Detach)观察者通知观察者的方法
ConcreteSubject:
具体被观察者,其中保存了所有需要被通知的观察者(有一个属性),并可以动态修改他的观察者(注册,删除),当其状态发生改变时,可以通知所有的观察者(Notify)

Observer:
抽象观察者,其中的Update方法提供被观察者通知时callback调用的。(可以降低类之间的耦合,提高内聚)
ConcreteObserver:
具体观察者,观察的对象是Subject(有一个属性),能接受Subject变化时发出的通知并更新自身的状态

Java中已经提供了Observer接口,直接实现改接口,即可形成一个观察者
Java中也提供了Observable抽象类,直接派生子类就是被观察者
(2)Visitor 访问者模式
对特定类型的object的特定操作(visit),在运行时将二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类
本质上是将数据和作用于数据上的某种/些特定操作分离开
为ADT预留一个将来可扩展功能的"接入点",外部实现的功能代码可以在不改变ADT本身的情况下通过delegation接入ADT。
ADT:


Visitor:

Visitor实现

使用:

4.状态模式
避免使用过多的if-else判断状态,同时也容易新增状态
State
为每一个状态设计一个类,这些类均实现了State这一公共接口,这个接口中包含了涉及状态改变的方法
状态类的设计采用单例模式,即每一个状态只能有一个实例。
Context
在Context中有一个属性(State state;)来控制状态及其改变,类中涉及状态改变的方法委托给具体的状态类来做,也可以保证在某些状态类下一些操作禁止的要求。但是state类仍要回调Context来完成功能,(低耦合,高内聚)所以状态改变的方法需要把Context传入作为参数。
也可以把状态改变的功能(最基本的功能)交给状态类来做,具体功能放在Context中完成,但是这样需要判断当前状态是否合适。
State模式的缺点之一是有许多空方法,因为State接口中的方法不是每一个状态都要实现,有些方法在对应状态下是被禁止。这一点和LSP原则有冲突。
5.Memento Pattern 备忘录模式
记住对象的历史状态,以便于“回滚”。


Memeto类只记录一个历史状态,在Originator中一次保存也只返回一个Memeto,同时恢复历史状态也可以利用Memeto。
Caretaker管理所有的历史状态,将回滚要求发给Caretaker,Caretaker返回对应的当时状态
比如说Caretaker用List保存所有的历史状态,回滚要求是向上回滚一步,那么返回当前状态对应的上一个状态Memeto给Originator即可。

浙公网安备 33010602011771号