导图社区 软件设计与体系结构
软件工程强调以工程化思想和方法开发软件,而软件设计作为软件开发过程中的核心活动之一,对开发出满足需要的高质量软件起关键作用,本篇导图详细概述了软件设计以及体系结构
编辑于2022-12-20 10:41:12软件设计与体系结构
软件工程和软件设计概述
软件
软件的本质
计算机软件,是由专业人员开发并长期维护的软件产品。
软件危机
软件神话
软件工程
软件工程
软件工程是:(1)将系统化的、规范的、可量化的方法应用于软件的开发、运行和维护,即将工程化方法应用于软件。(2)在(1)中所述方法的研究。
软件过程和软件工程实践
软件开发模型
瀑布模型
快速原型模型
螺旋模型
增量模型
喷泉模型
网络环境带来的影响
软件设计
软件工程中的设计
设计过程和设计质量
软件设计原则
抽象
体系结构
模式
模块化
信息隐蔽
功能独立
求精
重构
设计类
软件体系结构
什么是软件体系结构
包括构成系统的设计元素的描述、设计元素之间的交互、设计元素的组合模式以及在这些模式中的约束。
软件体系结构 = 构件 + 连接件 + 约束
软件体系结构的内容
设计阶段的软件体系结构
软件体系结构建模和UML软件体系结构建模和UML
软件体系结构建模概述
图形化模型
形式化模型
文档化模型
基于软件体系结构的开发
UML概述体系结构
UML的发展历程
UML的特点和用途
UML 2.0的建模机制
(1)语言定义精确度提高。这是支持自动化高标准需要的结果。自动化意味着模型将消除不明确和不精密,可以保证计算机程序能转换并熟练的操纵模型。
(2)改良的语言组织。该特性由模块化组成的,模块化的优点在于它不仅仅使得语言更加容易的被新用户所采用,而且促进了工具之间的相互作用。
(3)重点改进大规模的软件系统模型性。一些流行的应用软件表现出将现有的独立应用程序集中到更加复杂的系统中去
(4)对特定领域改进的支持。使用UML的实践经验,证明了其所为的扩展机制的价值。这些机制使基础语言更加简洁,更加准确精炼。
(5)全面的合并,合理化、清晰化各种不同的模型概念。该特性导致一种单一化,更加统一化语言产生,时UML2.0的图形符号也进行了一些调整
面向对象开发方法
基本概念
(1)对象
对象指的是一个独立的、异步的、并发的实体,它能“知道一些事情”(即存储数据),“做一些工作”(即封装服务),并“与其它对象协同工作”(通过交换消息),从而完成系统的所有功能。
(2)类
类的定义,包括一组数据属性和在数据上的一组合法的操作。
(3)继承性
广义地说,继承是指能够直接获得已有的性质和特性,而不必重复定义它们。
(4)多态性(Polymorphism)
在面向对象的软件技术中,多态性是指子类对象可以像父类对象那样使用,同样的消息既可以发送给父类对象也可以发送给子类对象。
(5)重载(Overloading)
有两种重载:函数重载是指在同一作用域内的若干个参数特征不同的函数可以使用相同的函数名字;运算符重载是指同一个运算符可以施加于不同类型的操作数上面。
(6)消息和方法
在面向对象领域,两个对象的交互是通过消息的发送和接收来完成的。消息分为简单消息、同步消息和异步消息
(7)聚集
在客观世界中有若干类,这些类之间有一定的结构关系。通常有两种主要的结构关系,即一般—具体结构关系,整体—部分结构关系。
面向对象方法的优势
1)支持软件的重用性。
重用性是指同一事物不经过修好或稍加修改就可以多次重复使用的性质。软件重用是软件工程追求的目标之一。
(2)提高软件可维护性和安全性。
面向对象方法通过对属性和操作的封装实现了软件工程倡导的信息隐藏的原则。
UML2.0 结构建模
类图
2种类元素(类和接口)
4种关系(依赖关系、实现关系、泛化关系和关联关系)
对象图
构件图
部署图
UML 2.0 行为建模
用例图
顺序图
通信图
交互概览图
交互概览图
时序图
状态图
活动图
面向数据流的软件设计方法
数据流图与数据字典
数据流图
数据流图(Data Flow Diagram,DFD)是一种建模技术,能以图形的方式刻画数据流从输入到输出的变换过程。数据流图通过描述对数据流进行变换的功能,来建立系统的功能模型;
数据字典
对数据流图中包含的所有元素的定义的集合构成了数据字典。它有4类条目:数据流、数据项、数据存储及基本加工。
实体关系图
状态迁移图
案例说明:教材销售系统
数据流图的建立
数据字典的建立
面向数据流的需求分析方法
自顶向下逐层分解
描述方式
步骤
5.6 面向数据流的设计方法
概念
变换分析
事务分析
启发式设计策略
设计优化
基础部分
类之间的关系
关联关系
聚合关系:部分可以单独存在的关系
组合关系
依赖关系
继承关系
实现关系
Java抽象类
接口类:没有构造方法
面向对象设计原则
开闭原则
依赖倒置原则
接口隔离原则
工厂方法模式
概述
介绍:(将选择与初始化一个合适的类的功能封装在一个专门的类的一个专门的方法中-委托).
选择一个类:选择一个合适的类的类层次结构的基础上,应用程序上下文和其他影响因素 创建该类的对象:所选类和实例化 以超类的类型返回该对象:返回父类类型的一个实例 不做任何其它事情
Client doesn’t need to know which concrete class has been instantiated (客户类只知道哪种类型的对象被创建了,而不必知道哪个具体的子类被初始化了;客户类只知道父类类型).
因为工厂方法将选择的类实例作为父类类型的对象返回,所以客户端程序不需要知道层次结构中类的存在。
两种方法
简单工厂方法模式【静态工厂方法】
工厂类:Creator (工厂类): 中心. 包含业务逻辑. 创建产品类对象.
最终成果:具体的JAva类趋势线接口或者是抽象类
优点: 一些逻辑被放在了工厂类里面 客户类不用自己创建对象 责任分离
工厂方法模式【动态工厂方法】
工厂类是一个借口,下面拥有实现类分别对应产品类
需要再监视器中对实现的产品类类型进行判断
使用的场景
A class contains a lot of conditional statements for creating objects (大量条件语句). A class uses its subclasses to specify which objects it creates (即,创建对象的任务分散在客户类的子类中,比较乱;可使用工厂方法模式将创建产品类的子类对象的责任分离出来). You want to localize the knowledge of which class gets created.
建造者模式
模式动机与定义
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
模式结构与分析
Builder:抽象建造者
ConcreteBuilder:具体建造者
Director:指挥者
Product:产品角色
模式实例与解析
建造者模式的结构中还引入了一个指挥者类Director,该类的作用主要有两个:一方面它隔离了客户与生产过程;另一方面它负责控制产品的生成过程。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象。
模式效果与应用
在以下情况下可以使用建造者模式:
需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
对象的创建过程独立于创建该对象的类。在建造者模式中引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类中。
隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
模式扩展
原型模式
模式动机与定义
在面向对象系统中,使用原型模式来复制一个对象自身,从而克隆出多个与原型对象一模一样的对象。
在软件系统中,有些对象的创建过程较为复杂,而且有时候需要频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在。
模式结构与分析
原型模式包含如下角色:
Prototype:抽象原型类
ConcretePrototype:具体原型类
Client:客户类
模式实例与解析
模式效果与应用
模式扩展
单例模式
模式动机与定义
单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。单例模式是一种对象创建型模式。单例模式又名单件模式或单态模式
模式结构与分析
单例模式包含如下角色:
Singleton:单例
模式实例与解析
模式效果与应用
系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。
客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
模式扩展
抽象工厂模式
介绍:如果包含多个产品层次类【结构相同】
对于每个Product层次类, 我们构造一个工厂层次类×
Two concrete factory classes, each is responsible for creating 3 objects.
理论:工厂类中有2个工厂方法;每个工厂方法创建一个Product类的对象
使用场景:当Client对象想要创建一族层次类的某个子类对象,而不想知道到底是哪个子类对象被创建了。
设计
创建型模式
适配器模式
装饰模式
组合模式
桥接模式
该模式不是简单地将这些类摆在一起,而是要提供这些类之间的关联方式。
介绍:将抽象部分与实现部分分开
理论
实现接口仅提供原始操作(例如,写入数据库,写入数据文件等等) The Implementor interface provides only primitive operations 抽象接口定义基于原始操作的高层操作(高层业务逻辑) The Abstraction defines higher-level operations based on these primitives
设计
结构模式
职责链模式
模式动机与定义
行为型模式概述
行为型模式(Behavioral Pattern) 关注系统中对象之间的交互,研究系统在运行时对象之间的相互通信与协作,进一步明确对象的职责
类行为型模式 对象行为型模式
模式定义
职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
职责链模式包含如下角色:
Handler: 抽象处理者
ConcreteHandler: 具体处理者
模式结构与分析
在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。
请求在这条链上传递,直到链上的某一个对象处理此请求为止。
发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
模式实例与解析
模式效果与应用
模式优缺点
职责链模式的优点
使得一个对象无须知道是其他哪一个对象处理其请求,降低了系统的耦合度
给对象职责的分配带来更多的灵活性
增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可
可简化对象之间的相互连接
职责链模式的缺点
不能保证请求一定会被处理
如果建链不当,可能会造成循环调用,将导致系统陷入死循环
对于比较长的职责链,系统性能将受到一定影响,在进行代码调试时不太方便
模式适用环境
在以下情况下可以使用职责链模式:
有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
可动态指定一组对象处理请求。
在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
模式扩展
中介者模式
中介者模式概述
模式定义
中介者模式(Mediator Pattern)定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
又称为调停者模式
在中介者模式中,通过引入中介者来简化对象之间的复杂交互
中介者模式是迪米特法则的一个典型应用
对象之间多对多的复杂关系转化为相对简单的一对多关系
属于对象行为型模式
中介者模式的结构与实现
模式结构
中介者模式包含如下角色:
Mediator: 抽象中介者
ConcreteMediator: 具体中介者
Colleague: 抽象同事类
ConcreteColleague: 具体同事类
中介者模式的实现
中介者类的职责
中转作用(结构性):各个同事对象不再需要显式地引用其他同事,当需要和其他同事进行通信时,可通过中介者来实现间接调用
协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致地和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装
中介者模式的应用实例
模式优缺点
中介者模式的优点
简化了对象之间的交互。
将各同事解耦。
减少子类生成。
可以简化各同事类的设计和实现。
中介者模式的缺点
在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。
在以下情况下可以使用中介者模式:
系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解。
一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象。
想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象交互的公共行为,如果需要改变行为则可以增加新的中介者类。
扩展中介者与同事类
中介者模式与迪米特法则
中介者模式与GUI开发
观察者模式
模式动机与定义
观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
观察者模式包含如下角色:
Subject: 目标
ConcreteSubject: 具体目标
Observer: 观察者
ConcreteObserver: 具体观察者
模式结构与分析
观察者模式描述了如何建立对象与对象之间的依赖关系,如何构造满足这种需求的系统。
这一模式中的关键对象是观察目标和观察者,一个目标可以有任意数目的与之相依赖的观察者,一旦目标的状态发生改变,所有的观察者都将得到通知。
作为对这个通知的响应,每个观察者都将即时更新自己的状态,以与目标状态同步,这种交互也称为发布-订阅(publish-subscribe)。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅它并接收通知。
模式实例与解析
模式效果与应用
模式优缺点
观察者模式的优点
观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
观察者模式在观察目标和观察者之间建立一个抽象的耦合。
观察者模式支持广播通信。
观察者模式符合“开闭原则”的要求。
观察者模式的缺点
如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
模式适用环境
一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
一个对象必须通知其他对象,而并不知道这些对象是谁。
需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制
模式扩展
(1) JDK1.1版本及以后的各个版本中,事件处理模型采用基于观察者模式的委派事件模型(Delegation Event Model, DEM)。
在DEM中,事件的发布者称为事件源(Event Source),而订阅者叫做事件监听器(Event Listener),在这个过程中还可以通过事件对象(Event Object)来传递与事件相关的信息,可以在事件监听者的实现类中实现事件处理,因此事件监听对象又可以称为事件处理对象。
事件源对象、事件监听对象(事件处理对象)和事件对象构成了Java事件处理模型的三要素。
(2) 除了AWT中的事件处理之外,Java语言解析XML的技术SAX2以及Servlet技术的事件处理机制都基于DEM,它们都是观察者模式的应用。
(3) 观察者模式在软件开发中应用非常广泛,如某电子商务网站可以在执行发送操作后给用户多个发送商品打折信息,某团队战斗游戏中某队友牺牲将给所有成员提示等等,凡是涉及到一对一或者一对多的对象交互场景都可以使用观察者模式。
命令模式
模式动机与定义
动机
将请求发送者和接收者完全解耦
发送者与接收者之间没有直接引用关系
发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求
模式定义
命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
模式结构与分析
命令模式包含如下角色:
Command: 抽象命令类
ConcreteCommand: 具体命令类
Invoker: 调用者
Receiver: 接收者
模式实例与解析
模式效果与应用
模式优缺点
命令模式的优点
降低系统的耦合度。
新的命令可以很容易地加入到系统中。
可以比较容易地设计一个命令队列和宏命令(组合命令)。
可以方便地实现对请求的Undo和Redo。
命令模式的缺点
使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
在以下情况下可以使用命令模式:
系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
系统需要在不同的时间指定请求、将请求排队和执行请求。
系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
系统需要将一组操作组合在一起,即支持宏命令。
模式扩展
宏命令又称为组合命令,它是命令模式和组合模式联用的产物。
宏命令也是一个具体命令,不过它包含了对其他命令对象的引用,在调用宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法,一个宏命令的成员对象可以是简单命令,还可以继续是宏命令。执行一个宏命令将执行多个具体命令,从而实现对命令的批处理。
迭代器模式
模式动机与定义
聚合对象的两个职责:
存储数据,聚合对象的基本职责
遍历数据,既是可变化的,又是可分离的
将遍历数据的行为从聚合对象中分离出来,封装在迭代器对象中
由迭代器来提供遍历聚合对象内部数据的行为,简化聚合对象的设计,更符合单一职责原则
迭代器模式(Iterator Pattern) :提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。
迭代器模式是一种对象行为型模式。
模式结构与分析
迭代器模式包含如下角色:
Iterator: 抽象迭代器
ConcreteIterator: 具体迭代器
Aggregate: 抽象聚合类
ConcreteAggregate: 具体聚合类
模式实例与解析
模式效果与应用
模式优缺点
迭代器模式的优点
它支持以不同的方式遍历一个聚合对象。
迭代器简化了聚合类。
在同一个聚合上可以有多个遍历。
在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足“开闭原则”的要求。
迭代器模式的缺点
由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
模式适用环境
在以下情况下可以使用迭代器模式:
访问一个聚合对象的内容而无须暴露它的内部表示。
需要为聚合对象提供多种遍历方式。
为遍历不同的聚合结构提供一个统一的接口
模式应用
Collection是所有Java聚合类的根接口。
在JDK类库中,Collection的iterator()方法返回一个java.util.Iterator类型的对象,而其子接口java.util.List的listIterator()方法返回一个java.util.ListIterator类型的对象,ListIterator是Iterator的子类。它们构成了Java语言对迭代器模式的支持,Java语言的java.util.Iterator接口就是迭代器模式的应用。
模式扩展
在JDK中,Iterator接口具有如下3个基本方法:
(1) Object next():通过反复调用next()方法可以逐个访问聚合中的元素。
(2) boolean hasNext():hasNext()方法用于判断聚合对象中是否还存在下一个元素,为了不抛出异常,必须在调用next()之前先调用hasNext()。如果迭代对象仍然拥有可供访问的元素,那么hasNext()返回true。
(3) void remove():用于删除上次调用next()时所返回的元素。
备忘录模式
备忘录模式概述
备忘录模式的定义
别名为标记(Token)模式
提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤
当前在很多软件所提供的撤销(Undo)操作中就使用了备忘录模式
备忘录模式包含以下3个角色:
Originator(原发器)
Memento(备忘录)
Caretaker(负责人)
备忘录模式的结构与实现
将Memento类与Originator类定义在同一个包(package)中来实现封装,使用默认可见性定义Memento类,即保证其在包内可见
将备忘录类作为原发器类的内部类,使得只有原发器才可以访问备忘录中的数据,其他对象都无法使用备忘录中的数据
备忘录模式的应用实例
实现多次撤销
有时候用户需要撤销多步操作
实现方案:在负责人类中定义一个集合来存储多个备忘录,每个备忘录负责保存一个历史状态,在撤销时可以对备忘录集合进行逆向遍历,回到一个指定的历史状态,还可以对备忘录集合进行正向遍历,实现重做(Redo)或恢复操作,即取消撤销,让对象状态得到恢复
备忘录模式的优缺点与适用环境
模式优点
提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤
实现了对信息的封装,一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动
模式缺点
资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免地需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源
模式适用环境
保存一个对象在某一个时刻的全部状态或部分状态,这样以后需要时能够恢复到先前的状态,实现撤销操作
防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象
策略模式 【行为型模式】
关心对象之间的责任分配,侧重描述通信模式
关于设计模式的调用
客户类代表调用者类
客户类调用该模式
对于不同模式,调用方式不同
依赖倒转原则
通过设计一个排序程序来介绍策略模式
优点
When a new algorithm is added, the existing Sorting class hierarchy doesn’t need to be changed and recompiled
When an algorithm is modified, the remaining classes in the Sorting hierarchy don’t need to be changed and recompiled
Both the client class and the implementation classes depends on the abstract interface
依赖倒转原则
策略模式理论
组成
策略strategy
声明一个通用的接口并且上下文使用这个具体的策略来进行调用具体的策略中实现的算法
具体的战略concertrateStrategy
上下文context
使用ConcreteStrategy对象配置
维持对策略对象的引用
可以定义一个接口,让stategy访问其数据。
使用时间
1) 当你要处理一些仅仅行为不同的相关的类的时候When many related classes differ only in their behaviors. Strategies provide a way to configure a class with one of many behaviors. 2) 当你要隐藏实现细节的时候 When you need to hide complex algorithm details When an algorithm uses data that clients shouldn't know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures. 3) 当你要取消许多条件语句的时候 When you want to cancel many conditional statements When a class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own Strategy class.
为什么要使用策略模式进行设计? 假设在用户在输入一组数据以后,程序将为你根据需要画出你所需要的图表类型。 各种图表,虽表现形式不同,但都显示同一组数据,功能是相同的。可以使用策略模式实现各种图表的显示。 将该根据用户输入的一组数据,利用各种不同的图标显示。为简单起见,我们在本例子中,只使用 条形图(Bar),和 饼图(Pie)。
context实现方式
向策略传递数据:当某算法被调用时,Context类将Strategy类所需要的所有数据一次性地传递完毕
Context将自己作为一个对象传递给Strategy类,然后Strategy类再利用该对象反过来调用Context类,以便获得某些数据与功能
工作机制
首先,客户端通常创建一个ConcreteStrategy对象并将其传递给上下文;
其次,上下文将客户的请求转发给策略。
此后,客户只与上下文交互(目的)。
优点
定义重用的相关算法
容易扩展
缺点
当更改现有算法实现或向组中添加新算法时,现有策略类层次结构和上下文都不受影响。
使用策略模式的设计示例
状态模式
关心对象之间的责任分配,侧重描述通信模式
例子
构建一个状态类层次结构,将每个状态封装到一个单独的类中
状态模式
定义客户程序需要的接口 保持状态类型State的引用,程序运行时,Context对象包含当前状态子类对象 可以包含部分业务逻辑
状态:定义一个接口,用于封装与上下文的特定状态相关联的行为。 状态子类:每个子类实现与上下文状态相关联的行为。
使用场合
当对象的行为依赖于状态,而该对象必须根据其状态(在运行时)改变其行为
当操作带有大量状态相关的、多部分的条件语句
协作关系
Context代表状态相关的请求 Context可将自己作为一个对象通过参数传递给状态对象,从而可让状态对象访问Context类的方法
客户对象先创建一个具体的状态子类的对象s,然后,在创建Context对象时,通过参数将s传递给Context对象。此后,客户程序就不必与该状态对象直接交互。 状态转换: Context类或具体的状态子类负责
建议
关于状态的转换的建议: 客户类Client不负责状态转换 客户类只创建一个“种子对象”,然后,传递给Context对象; 再由Context对象根据状态变化的情况,负责创建所有的其它的对象 或由State层次类决定状态的转换
优点
Easy in adding a new state class
它使状态转换显式
设计使用状态模式的例子
交互情况
状态类:负责转换状态,将当前具体状态传递给bankcontext
具体状态类
负责具体操作:存款取款
负责更新bankcontext中的balance
优点
可扩展性好
深入探讨
状态模式
状态相关的行为
状态对象可以负责更新配置给Context类 的状态对象
状态的选择/转换 依赖于Context/State对象
有状态转换
可以将一些业务逻辑包含在context类里面(包含状态转换)
策略模式
不是状态相关的行为,提供的是不同的功能
客户雷闯检测率子类对象传递给context对象
由应用类选择策略子类对象
没有状态转换
可以将一些业务逻辑包含在context类里面(没有状态转换)
访问者模式
行为模式
访问者模式的介绍
某些设计【关于好多层的那一种就是一个集成另一个但是他还有儿子孙子重孙子的那一种】
可维护性差
可扩展性差
改善设计:将具体的计算税收的方法从层次类中分离出来在层次类中保留数据维护方法 分离类的主要功能,即让“Tax”类独立于应用于它们的操作。
将每个子类中的计算功能封装在TaxCalculator类中
进一步改善:为了使上面的设计更加有效
TaxCalculator 改名 visit
所有汇总到计算类中的方法改名为visit×××
在所有层次类中增加visit方法
设计原因 增加访问者方法和接收方法
意图利用这两个方法在层次类和汇总类之间精心的设计接口
相互连接的方式:在客户类中定义访问者对象,并且使用父类定义某个tax层次类对象 通过使用accept方法而不是构造方法将访问对象拉入 将tax层次类对象传入访问者,告知是哪一个访问者来访问
访问者模式类图
为了批量访问元素节点使用了聚合结构包含多个节点
子主题
访问者模式
组件
访问这类:为每一个子类准备一个访问者方法
访问者决定要访问那个类【通过子类对象直接访问接口】
访问者模式构建
实现访问者类中接口中声明的所有操作 每个操作实现为结构中相应的对象类定义的算法片段。
提供算法环境、存储局部状态、积累遍历结构体的结果
元素
定义accept
具体元素
实现accept方法并且还可以实现其他一些方法
ObjectStructure(Program)可以省略
能列举出它的元素。 可以提供一个高级界面,允许访问者访问其元素。 可以是一个组合,也可以是一个集合,比如列表或集合。
该类可以使用一个聚合结构例如 ArrayList或者Vector将被访问对象集合在一起,然后再使用一个循环语句批量调用accept方法。
使用场景
子类种类相对固定
包含很多个子类
不同地类进行不同的操作
类的接口不同
深入探讨
使用时间
对象结构包含很多个子类,而这些类有不同的接口。你需要针对不同的类进行不同的操作
许多不同的且不相干的操作需要施加于对象结构,而你想要避免这些不同的操作污染这些类
Visitor让你把相关的操作定义在一个类中(例如,计算总价)。【计算机部件的例子】 当对象结构被许多应用程序共享时,使用Visitor将操作放在那些需要它们的应用程序中。
对象结构类很少改变(例如税收的种类很少改变),但是你需要经常地在这些结构体上增加新的运算(税率可能经常改变)。
注意要点
使用Visitor模式的客户端必须创建一个ConcreteVisitor对象,然后遍历对象结构,使用Visitor访问每个元素。 当访问一个元素时,它调用与它的类相对应的Visitor操作。元素将自身作为此操作的参数提供,以便访问者在必要时访问其状态。
优点
容易添加新的操作
相对的,不容易扩展类,不容易扩展结构
A visitor gathers related operations and separates unrelated ones. (例如,将计算总价格放在一个具体的visitor类中)
Related behavior isn't spread over the classes defining the object structure; it's localized in a visitor. Unrelated sets of behavior are partitioned in their own visitor subclasses.
缺点
Adding new ConcreteElement classes is hard. Each new ConcreteElement gives rise to a new abstract operation on Visitor and a corresponding implementation in every ConcreteVisitor class. ConcreteElementfunctionalities
重点
用于使得被访问者和访问者之间建立自动访问的accept方法,建立了两个层次类之间的关联,使得自动访问成为可能
注: 另外,类objectStructure类对于批量访问很重要。另外使用此类,可以使得客户类包含较少的条件语句。能够有效地做到责任分离。 结论: 要写好accept方法与objectStructure
调停者模式
理论
描述
面向对象应用程序有一些互动的对象组成,当对象比较少的时候对象之间可以相互交互
我们经常这样做,例如 在策略模式和状态模式里面,Context类的对象与Strategy层次类对象的耦合是双向的 在状态模式里面,Context类的对象与State层次类的对象之间的耦合是双向的
而随着对象数目的增加相互直接交互可能会导致混乱
比如说如果增加一个新的类,所有类的接口都需要进行改变
问题
负责方法调用
影响维护
减少复用性
解决:星型拓扑结构——调停模式
实现
Mediator类应该与参与者类(对象A, B, C, … ,H的类)之间有某种形式的关联, 而参与者类之间不应该有关联。
中介者必须拥有register方法
The mediator class must know all the concrete participate colleagues, and so this class needs a register method The register method can be used to let the mediator class keep all the participate objects
每个参与者类必须保持中介者的引用
so that it can call the methods in the mediator class to do something.
组成
程序的构件说明: Mediator:中介者的接口。 ConcreteMediator:具体的中介者,可以有多个具体的中介者。 Colleague:参与者对象接口 Colleague1, Colleague2:具体的参与者。可以有多个具体的参与者。
用途
减少对象之间直接的交互
中介者模式
中介模式表明抽象对象交互细节到一个单独的类,中介类负责所有对象交互 中介维持每个参与者类的引用 中介提供调用参与对象的方法
典型交互
任何两个不同对象之间的交互都通过Mediator类路由。 所有对象将它们的消息发送给中介(调用中介的方法) 然后,中介将消息发送到适当的对象,以实现应用程序的需求(然后在中介中调用每个其他对象的方法)。
Object B calls a method of mediator object. Then mediator object will call methods in objects E、F、G. Objects E, F, G may also call back the methods in Mediator object Mediator object may in turn call other objects 注:Object B may not know which object has been called
优点
参与者类的复用性更好
将对象间依赖关系移出单个对象可以增强对象的可重用性
子主题
参与者对象之间的关系可以由中介者子类对象调节
单元测试【参与者类】
because objects do not need to refer to each other directly
参与者类的修改
allows individual classes to be modified without affecting other classes.
缺点:降低性能
例子
航空宾馆旅游信息系统
三者之间的交互以及协议类型
相同的界面
三家企业信息共享:客户名字身份证号国籍并且有相同的界面搭建
三家企业之间的关系是相互通知的关系
使用中介者模式
负责注册企业【含有每个参与者的引用】
更新每个参与者中的信息
添加可能的顾客
实现细节
写一个中介者类
编写中介类,并声明具有参与中介模式设计的所有对象类型的私有变量 私人hotelGui: hotelGui; 私人airlineGui: airlineGui; 私人tourGui: tourGui
写注册方法
在中介类中,编写所有注册方法来注册所有参与的对象。例如,参与的对象类型应该分别包含在注册方法的参数中 registerHotelGUI (HotelGUI hg) registerAirlineGUI (AirlineGUI ag) registerTourGUI (TourGUI tg)
在每个注册方法内部,将从参数传递的对象赋值给相应的私有成员。例如, registerHotelGUI (HotelGUI hg) { hotelGui = hg; }
注册进了中介者对象中
main方法的实现
Create mediator object. Inside the client class, an object of the mediator class should be created Create participant object. And then the objects for all the participating classes should be created with the just-created object passing in though the parameters
观察者模式
当数据有变化时,OceanData对象通知DataAnalizer对象 调用其中相应的函数
引用
改善调用方式,当数据有变化的时候,被观察者通知观察者,由观察者进行数据更新
大气监测显示的例子:绘制浓度随时间的变化曲线
概念
步骤
1. 注册观察者对象进入被贯彻着的列表【属性】
2. 当有变化的时候通知观察者对象
3. AirDSP 子类对象绘图并显示相应数据
优点:松散的耦合
容易修改代码
当需要修改Air代码的时候,AirDsp层次类不受影响 当需要修改AirDsp代码的时候, Air类不受影响
容易扩展
容易在AirDsp中增加新子类,而 原来已经存在的所有的类都不受影响
观察者模式:对于设计在观察者和被观察对象之间的一致的通信模型有用
使用场景:当你可以吧程序中的对象划分为观察者和被观察者的时候可以使用观察者模式进行设计
观察者:一组依赖于别观察者的对象
类图
双方需要获知的:观察者要知道被观察者的引用,被观察者要有观察者的引用
笔记:一个主题可以有多个观察者,主题包含一个动态列表记录观察者
主题无法维护此类观察者的静态列表,因为给定主题的观察者列表可能会动态变化)。
观察者模式必须包含的活动
Observer / 客户注册 register itself: Any object with interest in the state of the subject needs to explicitly register itself as an observer with the subject. Observable must notify the observers: Whenever the subject undergoes a change in its state, it notifies all of its registered observers. An observer can query about the state of the obsevable:【可以调用一些方法】 Upon receiving notification from the subject, each of the observers queries the subject to synchronize its state with that of the subject’s.
观察者/客户注册登记本身: 任何对主体状态感兴趣的对象都需要显式地将自己注册为主体的观察者
Observable必须通知观察者: 当主体的状态发生变化时,它会通知所有注册的观察者
一个观察者可以查询关于obsevable的状态:【可以调用一些方法】 在收到来自主题的通知后,每个观察者都会查询主题以使其状态与主题的状态同步。
通知观察者的两种策略
观察者模式有很多变形
The push model(将观察者所需数据全部推给观察者, 例如, update(Object a)): The subject should send the state information that the observers may be interested in
The pull model(主题提供接口,供观察者访问,例如 update(Observable obs)): The subject should provide an interface that enables observers to query the subject for the required state information to update their state.
优点
可以动态添加观察者不影响主题
当主题的状态或者逻辑发生变化的时候
如何使用观察者模式
一个对象的状态改变必须反映在另一个对象中,而你又不想让两个对象保持高耦合 你设计的框架将来需要添加许多观察者,而你希望以最小限度地改变程序
Java支持
提供了被观察者类【实现了addObserver、setChanged、notifyObservers方法】
提供了观察者类
实现了既推又拉的方式
例子
温度转换的例子
设计1 用户定义的观察者模式
设计要点:设计两个接口类Observeable和Observer,声明观察者模式所需要的方法
在被观察者中,需要实现的方法:notifyObservers();register(Observer)
在观察者实现类中需要实现的方法是既推又拉的方法
设计2 使用Java API支持的观察者模式
客户类. In the TestObserverObservable, use addObserver(observer:Observer) to add an observer CelsiusGUI, FahrenheitGUI, and KelvinGUI to the TemperatureGUI object 被观察类. In class TemperatureGUI, use setChanged() and notifyObservers() together to notify the observer that the state of the Object TemperatureGUI has changed, and then the update(o: Observable, e: Object) method in CelsiusGUI, FahrenheitGUI, and KelvinGUI objects will be automatically invoked to update display of temperature. In the update method, in turn, observable can be called to check the state change.
客户类. 在TestObserverObservable中,使用addObserver(observer: observer)添加一个观察者CelsiusGUI, FahrenheitGUI和KelvinGUI到TemperatureGUI对象 被观察类. 在类TemperatureGUI中,一起使用setChanged()和notifyObservers()来通知观察者对象TemperatureGUI的状态已经改变 然后CelsiusGUI, FahrenheitGUI和KelvinGUI对象中的更新(o: Observable, e: Object)方法将被自动调用来更新温度显示。 在update方法中,可以反过来调用observable来检查状态的变化。
在client类中,创建被观察者对象、观察者对象并且把观察者对象添加到被观察者对象中,通知观察者
行为模式
行为模式关心算法和对象之间的责任分配。 它关心的不是仅仅描述对象或类的模式,而是要更加侧重描述它们之间的通信模式。 行为模式刻画了很难在运行时跟踪的复杂的控制流。该模式将软件开发者的注意力从控制流转移到对象相互关联的方式方面。
设计模式
L1 MVC 设计模式/体系结构
介绍
MVC设计模式:将来可能会添加一些功能 在输入、信息显示方面
希望能够把所有的业务逻辑都封装到一个类里面
解决方法:使用MVC设计模式
Model:业务逻辑
受到Controller控制
View:输入输出图形界面;用户视图
相互控制
Controller:图形控制器:用户输入
相互控制
理论
架构形模式
在用户和应用程序之间的交互划分成三种角色
相互之间的关联 显式调用、隐式调用或其他机制(例如HTTP协议)
Model的责任:整个业务逻辑
业务逻辑实现
从数据库中读取数据和并将数据存储到java程序中定义的某个变量里面
之后负责数据验证并且将数据缓存如数据库
VIEW
捕捉用户输入
向控制器分发处理请求
显示输出【根据控制器的指示】
Controller
接收来自用户的请求【view过来的、用户控制的请求】
调用model业务逻辑
调用view展示执行结果
两个主要的分离
表示从模型中分离出来
控制器从view中分离出来
数据更新
改变-传播机制
可以由观察者模式实现,保证了用户界面和模型的一致性
如果一个view通过控制其改变了model,那么所有view都必须反应
数据发生变化的时候,model通知所有的view数据改变
views可以遍历model中的数据,以便及时更新显示数据
注意:view可以不必调用Controller,
注意:controller包含model、view的引用,view包含model、controller的引用,Model包含的至于偶view的引用
如果通过观察者模式实现改变传播机制的事后,model就是subject,view是observer
优点
容易增加或者改变视图
容易独立的更新各个独立的软件模块
代码容易开发和维护
业务逻辑容易测试
非可视化比可视化的更容易测试
整体的过程
控制器选择试图并且获取用户输入【controller和view之间的交互】
调用model里面的业务逻辑 controller
Model通知view更新数据
view调用model中的方法获取数据,因为需要更新视图
例子
采用MVC模式使用挂插着机制,用户输入界面两个显示界面分别独立显示
L2 层次结构
概念
层次系统是按照层次组织的,每一层都为上面的一层提供服务并接受下一层的服务
限制:交互仅仅在相邻层按照特定方向进行
典型应用领域
优点
基于逐层增加的抽象级设计,允许实现浙江复杂的问题进一步划分为一系列逐渐增加的抽象级别的步骤
支持更新
支持复用
同一层有不同的实现,只要它们相互支持到相邻的相同接口
通过标准层接口,可以由不同的软件开发团队构建
缺点
不是所有系统都能够很容易的实现通过分层的方式构建
很难找到抽象层次
三层软件架构
运行在互联网上的三层架构:客户端服务器架构
通用三层架构
表现层
图形用户界面
用户输入用户请求用户请求的返回结果等等
调用应用层
但是应用层从来不会调用表示层的功能
应用层
业务逻辑层,主要包含应用的业务逻辑,实现了商用的功能
组件封装了应用的核心数据和功能
不能直接访问数据库,需要调用永久数据存储层的相应功能
永久数据存储层
数据库的访问和永久数据存储到数据库的功能
Java实现中,包含了利用JDBC写的数据库访问代码
不能够调用应用层和现实层,只能将执行应用层的请求所得到的数据库访问结果返回给显示层
三层软件结构和MVC的比较
两种架构相似之处如下: 都是由三部分软件模块组成的 三层架构的显示层与MVC架构的View类似; 三层架构的应用层与MVC架构的Model类似。
区别
各个模块之间的调用关系不同
三层体系结构是线性的
MVC架构是三角形的
view对象放松更新给controller对象,controller更新model对象并且view对象直接的从model对象中获得更新
对于数据库的访问方式不同
MVC架构没有制定专门的数据库访问模块,一般情况下是model,但是controller也可以直接访问数据库
关于控制模块
层次架构中没有,一般是在应用层立面单独指定一个类似的控制模块
其主要责任是接收从显示层输入的用户请求,然后根据请求的类型,决定调用应用层的其它组件。
观察者模式的使用
应用层和表示层之间使用观察者模式
导致应用层对现实层的调用
违背了层次架构的原则
但是这个小小的违规带来的是观察者机制更新图形界面的效率
model和view之间使用
例子学习
自动机器人控制系统
感知
控制
规划路径
L3 主程序-子程序系统与面向对象系统
发展
非结构化编程
使用goto语句
所有代码都在一个主程序里面
引入:迭代、分支和GOTO
缺点
很难追踪程序逻辑; 很难合并其它代码; 修改代码并不容易(都是goto惹的祸); 很难测试特定部分的代码。
结构化编程
定义
子结构、块状结构、循环结构
试图抛弃Goto语句
定理
序列、选择、迭代结构
调用返回体系
他的子类型
主程序和子程序 (main program and subroutine) 体系结构
面向对象系统
通性
采用分割【divide】征服策略
减少复杂度,分成小的系统
调用返回架构执行顺序被单线程控制
具有主函数{PPT17}
软件组件构成的
满足的规则:子程序与附程序之间返回的是控制权
在调用一个子程 序之后,控制权返 回到调用者子程序
软件组件只有得到了控制权之后,才能运行。
主程序和子程序
组成
一个主程序和一些分层组织的子程序组成
主程序调用高层子程序; 高层子程序调用底层子程序
一个子例程的正确性通常取决于它调用的子程序是否正确
子程序:子程序(也称为过程)是较大程序中的一部分代码,它执行特定任务,相对独立于其余代码。子程序是现在的函数与方法的简单情况。
结构化的设计使用自顶向下的功能化设计;C语言的设计风格;
该系统从功能化的角度进行设计,从高级视图开始,逐步细化为更详细的设计【逐步划分,直到函数简单】
系统依赖于一组子程序 (函数),没有对象的概念
优点:自顶向下的方法是非常成功的设计方法 对于10万行以下的代码的程序设计没有问题。
缺点:当程序超过10万行代码的时候,该方法表现很差。
代码开发变得越来越慢; 而且测试软件和保证其可靠性变得越来越困难。
问题
功能化设计不容易进化(可扩展性差) 实际的系统很难按照功能化的观点刻画. 功能化丢失了数据. 功能化设计的程序复用性比较差.
面向对象设计
不是结构化设计
是由对象构成的,不是相互调用的函数组成的,每个对象都有自己的操作集
程序架构
原理/思想/原则:面向对象设计的原理:基于信息隐藏
概念
对象:: An Object is something with a State (i.e., it holds Data), and Semantics (i.e., rules for changing its state).【语义】
性质
封装
继承
动态绑定
指在执行期间(非编译期)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
复用和维护
其他
对象是现实世界实体的抽象. Objects are abstractions of real-world or system entities and manage themselves 对象之间互相独立. Objects are independent (from encapsulation point of view) 系统功能由对象服务【函数和方法全体】表达. System functionality is expressed in terms of object services (functions) 取消了共享数据区. Shared data areas are eliminated 对象可以是分布式的. Objects may be distributed 对象可以按顺序执行或者并行执行. Objects may execute sequentially or in parallel
例子
L4 数据流系统与批处理架构
数据流的概念
定义:满足以下条件的系统
数据的可用性控制着计算 设计的结构由数据在进程之间的有序运动决定的 数据的模式是明确的
有数据的时候【数据到达的时候被激活,无数据的时候就休眠】
一般来说数据可以按照任意方式流动
关于控制流
关注程序中控制流轨迹
数据可能伴随控制,但是数据不是主导
我们关心程序的执行顺序
设计方面注意事项
数据的流动方式
随着设计的流动,控制被激活
设计的注意事项
数据的可用性
数据变换
数据延迟
数据流开发方法论
将系统分解为一些模块 Decompose system into modules − Abstraction isolates complexity【抽象】 − Operations performed on data objects 将模块组合成图 Compose modules into a graph − Connect modules forming directed graph − Interfaces are negotiated to match data types 运行该图 Run the graph − Data flows between the modules − scheduler automates parallelism − memory manager optimizes memory usage
批处理软件体系结构概念
定义
批处理是由一系列处理步骤构成的
每一步都将会卓一些操作在输入存储上去获得一些有用的信息或者形成资源存储的内容,然后存储最后的结果信息
性质
处理步骤之间是独立的程序,没有交互
每一步需要完整的运行完成之后才能够进行下一步
数据作为一个整体在各个步骤之间传输
理解为特殊的数据流
典型应用
业务数据库处理主要由数据库更新控制:预定类型的离散交易;周期性定期报告;对错误请求的特殊处理。
在批处理中的程序案例
千年虫和政治问题
图像处理
人口信息处理程序
L4-2 管道过滤器架构
概念
管道【传输数据的】+过滤器【对数据进行处理的一个程序】
过滤器功能
添加信息【符合条件的信息添加进去】
变换数据:改变数据的表达形式
流对流变换:变换完之后直接往下写,不保留状态
不保留状态:忘记已经发生的事情
管道动能
中介
单向流
数据传输图
整体运行机制
运行管道与过滤器,一直到没有任何计算Run pipes and filters until no more computations are possible 数据搬运是中介,Action is mediated by data delivery
数据以数据流的方式从左端流入,流经各个过滤器,对数据进行处理;对于处理完的数据,立即写入到下游管道.
例子
千年虫和政治问题
以流的形式写:一次只写一个字符【字符流、数据流】
编译器
编译器示例的典型架构是下一页描述的管道和过滤器架构。
编译原理环节
Unix操作系统
带分支的管道-过滤器架构
对比
批处理:处理过程之间互不调用【与面向对象区别,箭头代表数据流动】
数据处理方式不同
批处理架构,数据以 块状 形式传输, 管道-过滤器架构,数据以 流 的形式传输
所处理的数据量不同
批处理架构,数据量是有限的 管道-过滤器架构,数据量是无限的
优缺点
复用(reuse)性好: It supports reuse, since each filter can function in isolation 容易扩展(Easy evolution): New functions are easily added to the system by inserting filters at the appropriate points in the processing sequence.【别的过滤器不受影响】 容易修改(Easy modification): it’s easy to modify the system since filters are logically independent of other filters.
过滤器之间互不调用
人-机交互差 (Poor Interaction) 纯粹的管道-过滤器架构设计的软件没有人-机交互;但是在实际应用中,可以改善此架构,例如,对于每个过滤器,都可以增加一个用户图像界面 浪费内存 (Waste of space):【现在可能没有了】 由于每个过滤器必须不断地将数据(流)从输入端口复制到其输出端口,因此对于内存空间使用空间效率低下。
L5 案例分析
千年虫和政治问题
不使用goto即可实现任何代码