面向对象分析与设计(OOAD)期末复习 知识点总结

参考书籍:《Applying UML and Patterns 3rd》

Introduction

软件架构的定义:

一个程序或计算系统的架构,是该系统的结构,由组件、组件的外部可见的特性、组件之间的关系组成。

架构是一个软件系统的组织结构,可以递归地分解为多个通过接口相互作用的部件。关系定义接口的连接、约束定义部件的集成。部件包括类、组件、子系统。

面向对象: 是将系统看作一组相互作用和关联的对象并建模。

面向对象的特点:系统由相互关联对象组成;通过对象对系统进行描述和建模

Thinking in OO

OOA: 发现并描述问题领域里的对象或概念(找出问题领域里的概念类)

OOD:定义软件对象,以及它们之间如何协作完成功能的

OOD的输入:包括领域模型/概念模型、系统顺序图、用例图、补充规格说明等。
OOD输出:Interactions(用例实现–SSD), class diagram(类图),交互图(顺序图、通信图) etc

领域模型/概念模型: 对问题领域的对象或现实事物的可视化表示。

CRC表示职责:Class + Responsibility + Collaboration

Unviersal steps of OOD:

  1. After identifying your requirements and creating a domain
    model
    ,(明确需求 创建领域模型)

  2. then add methods to the appropriate classes, (为适当的类添加方法)

  3. and define the messaging between the objects to fulfill the
    requirements(定义对象之间的消息以实现需求)

OOAD:

  1. Use Case
  2. Domain
  3. Interaction
  4. Design Class Diagram
    1. LRG 低表示差异,既概念类与软件类差异不大

OOAD最基本过程

在这里插入图片描述

OOAD Review

类和对象关系: 类是共享相同属性、操作、方法、关系或者行为的一组对象的描述符。

多态: 同一类族的不同对象,可以用不同的行为处理同一条消息。比如,父类定义的方法、操作,子类可以重新实现(override)。

组合与聚合: 聚合–整体与部分是has-a的关系,部分可以独立于整体存在;组合–整体与部分是part-of的关系,部分无法独立于整体存在,整体没了部分就没了,整体对象控制部分对象的生命周期。

Q:为什么能用组合的地方不用继承?

A:如果使用继承,父类和子类之间耦合较重,组合相对继承的耦合性更低,组合的可维护性更强。

封装:隐藏对象的实现细节的过程。 接口是唯一访问对象数据的方法

接口: 为类或者构件设定了一个外部行为规范

抽象: 过滤掉对象的一部分特性和操作,直到只剩下你所需要的属性和操作。

抽象的两个重要指标:内聚性和耦合度

  • 内聚性:如果抽象能够简洁地代表一种清晰的概念,那么抽象是内聚的。

  • 耦合度:即与相关联的类的耦合程度。如果耦合度高,那么重用性就低,因为该抽象与系统中的其它模块相关以致于很难单独维护。

UP Process

RUP-Rational Unified Process 统一开发过程

RUP最重要的它有三大特点:1)软件开发是一个迭代过程,2)软件开发是由Use Case驱动的,3)软件开发是以架构设计(Architectural Design)为中心的。

SDP: Software Development Process 软件开发过程

SDLC: Software Development Life Cycle 软件开发生命周期

瀑布生命周期(Waterfall Lifecycle):试图在编程前详细定义所有或大部分需求。通常于编程前创建出完整的设计。

迭代生命周期(Iterative lifecycle): 在这种生命周期中,开发被组织成一系列固定的短期小项目,称为迭代每次迭代都经过测试、集成为可执行的局部系统。每次迭代都有各自的需求分析、设计、实现和测试活动。

Q: 为什么迭代开发不是面向对象的?
A:迭代开发 是一种开发过程,不是设计方法当然也不是面向对象的。面向对象是一种设计方法在每一次迭代中都可以用面向对象或其他的设计方法完成设计工作

理解UP的4个阶段: 初始-细化-构建-交付

Inception: approximate vision, business case, scope, vague estimates.大体上的构想、业务案例、范围和模糊评估。(分析项目的可行性,不是定义所有的需求)

  • 包括需求分析、关键非功能性需求的确定等。
  • 10% high risk list:(1)具有重要的架构意义;(2)具有高业务价值;(3)具有高风险
  • 初始阶段不是需求阶段,而是研究可行性的阶段

Elaboration: refined vision, iterative implementation of the core architecture, resolution of high risks, identification of most requirements and scope, more realistic estimates. 已精华的构想、核心架构的迭代实现、高风险的解决,确定大多数需求

Construction: iterative implementation of the remaining lower risk and easier elements, and preparation for deployment. 对遗留下的风险较低和较简单的元素进行迭代实现,准备部署

Transition: beta tests, deployment. 调试&部署

进化式需求 Evolutionary Requirements

  • Functional: behavioral
  • Non-functional: others 非功能需求 如安全性,可拓展性等

SRS : System Requirements Specification

一个好的SRS应该是: 明确的;完整的; 可证实的;一致的;可修改的;可追溯的。

FURPS+:Function Use Reliable Performance Support

SSD:系统顺序图

把要开发的整个系统看作一个黑盒子,在系统边界提供接口,研究与参与者的交互

Op Contract

对于一些复杂的系统操作(细粒度软件的系统操作),需要编写操作契约以获得更多分析细节。

Design by Contract (DbC)

  • Software reliability: requires precise specifications which are honored by both the supplier and the client.
  • DbC uses assertions (pre and postconditions, invariants) as a contract between supplier and client.
  • DbC works equally well under inheritance.

细粒度软件类的操作,需要定义“契约”,契约不是针对整个系统的操作(大粒度软件类)

大部分契约在细化阶段进行编写。只对最复杂最微妙的系统操作编写契约(获得分析细节)。

操作契约使用前置条件和后置条件的形式,描述领域模型里对象的详细变化,并作为系统操作的结果。

格式:

  • 操作:操作的名称和参数
  • 交叉引用:会发生此操作的用例
  • 前置条件:执行操作前,对系统或领域模型对象状态的重要假设。这些假设比较重要,应该告诉读者
  • 后置条件:最重要的部分,完成操作后,领域模型对象的状态创建实例,形成关联,修改属性。过去式。

GRASP —— 抽象的设计原则(理念)

GRASP全称: General Responsibility Assignment Software Patterns 通用的职责分配原则

GRASP原则将用于产生可维护、可重用、可理解和易于开发软件

GRASP原则可以帮助设计人员理解面向对象设计的本质,并以一种有条理的、理性的、可解释的方式应用这些设计原则。

OOD的输入:包括领域模型/概念模型、系统顺序图、用例图、补充规格说明等。

OOD输出:Interactions(用例实现–SSD), class diagram(类图),交互图(顺序图、通信图) etc

RDD: 职责驱动设计 Responsibility-Driven Design —— 设计时考虑对象做什么(行为职责)、或者知道什么(认知职责)

-Doing (行为职责)

  • Do it yourself: such as creating an object or doing a calculation 自身执行一些行为,如创建对象或计算
  • initiating action in other objects 初始化其他对象
  • controlling and coordinating activities in other objects 控制&协调其他对象

-Knowing(认知职责)

  • knowing about private encapsulated data 对私有封装数据的认知
  • knowing about related objects 对相关对象的认知
  • knowing about things it can derive or calculate 对派生/可计算数据的认知

The translation of responsibilities into classes and methods is influenced by the granularity of the responsibility. (职责的粒度影响到职责到类与方法的转换)

大粒度职责有数百个类与方法,而小粒度职责可能只有一个方法(一个类)。

职责是一种抽象,而方法实现了职责。

Pattern: Name + Problem + Solution

Rule1: Creator

Name: 创建者

Problem: 谁负责创建对象?

Solution: Assign class B the responsibility to create an instance of class A if one of these is true (the more the better) :

  1. B “contains” or compositely aggregates A B包含A
  2. B records A B记录A
  3. B closely uses A B频繁使用A
  4. B has the initializing data for A that will be passed to A when it is created (B is an expert with respect to A)
    如果有一个以上的选项适用,通常首选 聚集 或包含A的类

Rule2: Information Expert

Name: 信息专家

Problem: 给对象分配职责的基本原则是什么?

Solution: Assign responsibility to the class that has the information necessary to fulfill responsibility(把职责分配给具有完成该职责所需信息的那个类)

Rule3: Low Coupling

Name: 低耦合

Problem: 如何减少因变化产生的影响

Solution: 在分配职责时,始终保持低耦合(通常用作我们评估方案的原则)

下面这些情况会造成类 A、B 之间的耦合:

a、A 是 B 的属性
b、A 调用 B 的实例的方法
c、A 的方法中引用的 B,例如 B 是 A 方法的返回值或参数。
d、A 是 B 的子类,或者 A 实现 B

为什么期望 低耦合?

低耦合往往能够减少修改软件需要的时间、工作量和缺陷

Note: 为什么信息专家会导致低耦合?因为信息专家在分配职责时,是将职责分给具有该职责信息的类,所以模块自己能把大部分职责完成,不需要关联其他模块。

没有任何耦合也是不行的,这样系统中模块都是离散的。我们的原则是要保证低耦合,但要有一些耦合,系统仍然是多个对象协作的整体。

Q: 什么情况下允许高耦合/低内聚?
A:与稳定的,得到大众广泛认可的元素/模块直接耦合是可以的。比如Java J2EE应用程序可以安全地将自己与Java库直接耦合。便于客户使用。

Rule4: High Cohesion

在分配职责时,始终保持高内聚

Goal: (专注 做少量事情)

内聚:模块内操作之间联系的紧密程度

耦合:两个子模块之间联系的紧密程度

为什么内聚要越高越好?一个模块自己就能把职责做完

Rule5: Controller

Name: 控制器

Problem: 谁负责在UI层之上 首先接收和处理系统操作消息?

Solution: Assign the responsibility to a class representing one of the following choices:

  1. Facade(外观) Controller: 整个系统、根对象

represents the overall system, a root object, a device that the object is running within, or a major sub-system(为子系统中的一组接口提供一个一致的界面)

  1. Use Case or Session Controller: 代表用例或会话

represents a use case scenario within which the system event occurs

Delegation pattern 委派模式——负责任务的调度和分配任务

​ UI层通常收到消息并不自己处理(不包括应用逻辑),而是委托给其他对象处理。

Rule6: Polymorphism

Name: 多态

Problem: 如何处理基于类型的选择?

Solution: 使用多态操作,根据类型变化,动态地分配职责

GoF相关模式;Adapter, Command, Composite, Strategy

Q:多态与PV之间的关系。

A:多态是实现PV的方式之一。多态提供一种机制(接口),使系统的局部能适应类型的变化。只要实现了父类的接口,子类实现的细节可以多种多样,而实现的改变不会影响使用接口的人,使得我们不用改变现有代码就能基于类型提供不同的行为。

Rule7: Pure Fabrication

Problem: 既不违反低耦合、高内聚或其他的原则,但依据信息专家原则获得的解决方案又不合适的情况下,如何把职责分配给对象?

Solution: 把高度内聚的职责分配给人为虚构出来的一个类,(强调)这个类在领域模型里没有对应的概念

GoF相关模式;Adapter, Command, Strategy

Rule8: Indirection

Name: 间接

Problem: 为了避免两个或多个事物之间的直接耦合,应该如何分配职责?

Solution: 把职责分配给中介对象(通常是抽象类或接口),以在其他组件或服务之间进行协作,从而使它们不直接耦合。

GoF Example: Adapter, Facade, Observer

Q:纯虚构与间接的区别?
A:出发点不一样:

纯虚构: 把功能相对集中的、专一的职责分配给一个新定义的虚拟的类,而在领域模型中没有这个类对应的物理概念;一般用于将功能过于强大的类再细分,划分出单一功能的类,实现高内聚低耦合。

间接: 是为了把两个类之间的直接耦合改为通过一个中间概念,这个中间概念一般为 接口、或者抽象类。

Rule9: Protected Variations

Name: 隔离变化

Problem: 如何设计 使得内部的变化或不稳定性不会对其他元素产生不良影响?

Solution: 使用一个稳定的接口来封装变更的可以预知点。如数据封装,多态。接口等。

识别在程序中的那些多变的特征,并且把它们和稳定的特征分离开来。

Object Design Examples with GRASP

使用GRASP进行对象设计

用例实现:用系统顺序图的方式展示用例的功能在设计方案下能否实现

MVC:

  • M即Model模型是指模型,表示业务规则。

  • V即View视图是指用户看到并与之交互的界面。似我们说的 Panel。

  • C即Controller控制器,接受来自UI的请求,然后进行处理。负责系统的内部的控制、协调。

  • 使应用程序的输入、处理和输出分开。

注:MVC是一种架构风格,关注的是软件组织架构,而不是设计模式。

Refactor

可见性 Visibility:

一个对象看见其他对象或引用其他对象的能力。

  • 属性——B是A的属性
  • 参数——B是A中方法的参数
  • 局部——B是A 中方法的局部对象
  • 全局——B是具有某种方式的全局可见性

重构重写或重新构建已有代码的结构化和规律性方法。但不改变系统的外部功能。本质上是一小步保留行为的转换每次转换都要重新执行单元测试

重构是为了得到优秀的代码:

  • 去除冗余
  • 改善清晰度
  • 增强可读性
  • 提升代码结构

TDD: Test Driven Development 测试驱动开发——TFD + Refactor

首先编写测试,并通过不断地重构代码以改进质量。

Refactor: Name the Condition 引入解释变量,将表达式部分或完整结果置入临时变量中,该变量名能够说明表达式的目的。

开闭原则(OCP)

Def. 模块应该同时开放(可拓展性)和封闭(对影响客户的更改,尽量不改现有的代码)。

当应用的需求改变时,在不修改软件实体的源代码的前提下,可以扩展模块的功能,使其满足新的需求。

可以提高:可拓展性、可复用性、可维护性。

依赖倒置(DIP)

Def. 高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。

依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。

相对于面向过程编程的上层依赖下层模块的方式,在面向对象设计时,上层和下层都依赖抽象,故称为 “倒置”。本质就是面向接口编程,而不是面向实现(即底层)编程

迪米特法则(LoD)

Def. 如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。(开闭)

只与你的直接朋友交谈,不跟“陌生人”说话。

迪米特法则中的“朋友”是指:当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象同当前对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。

里氏替换原则(LSP)

Def. 通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。子类继承父类时,除添加新的方法、完成新增功能外,尽量不要重写父类的方法。

对里氏替换原则的定义可以总结如下:

  • 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
  • 子类中可以增加自己特有的方法
  • 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松
  • 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等

GoF —— 具体的设计模式(代码)

设计模式

是一套被反复使用、得到大众认可的代码经验的总结。 它关注系统中类、对象、接口的关系,描述设计过程中经常发生的问题,并提出解决方案。目的是生产可重用、可维护、易于理解(代码可读性)和开发的软件产品。

软件设计模式(Software Design Pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。**其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。

主要是为了:

  • Reuse Design 重用设计
  • Common Vocabulary 为设计提供共同的词汇,便于交流
  • Easy Documentation 编写开发文档更加容易
  • Easy refactor 应用设计模式可以让重构系统变得容易

SingleTon 单例模式

  • 名称:单实例类
  • 问题:希望只有唯一实例的类。对象需要全局可见性和单点访问。
  • 解决方案:通过静态方法返回单实例

单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

SingleTon的三个关键点

1)私有的: 构造函数(防止被默认地实例化)

2)私有的:成员变量,记录这个单实例

3)公有的get函数:没有实例时创建它;已有实例则返回该实例。

相关模式:单实例模式通常运用于工厂对象和外观对象。

  • Abstract Factory, Builder, and Prototype can use Singleton in their implementation
  • Facade objects are often Singletons because only one Facade object is required

Adapter 适配器

Problem: 如何解决不相容的接口问题,或者如何为具有不同接口的类似构件提供稳定的接口?

Solution: 使用 中介适配器对象,将原有接口转换为其他接口。

一个类的接口转换成客户希望的另外一个接口。Adapter模式使原本由于接口不兼容而不能一起工作的那些类可以一起工作。

img
相关模式:隐藏外部系统的资源适配器可视作外观对象。

Facade 外观模式

Problem: 对一组完全不同的实现或接口需要公共、统一的接口。可能会与子系统内部的大量事物产生耦合,或者子系统的实现可能会改变。怎么办?

Solution: 对子系统定义唯一的接触点——使用外观对象封装子系统。该外观对象提供了唯一和统一的接口,并负责与子系统构建进行协作。

外观(Facade)模式是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体细节(隔离变化),这样会大大降低应用程序的复杂度,提高了程序的可维护性。

适配器与外观模式的区别

适配器:将一个接口转换为客户希望的另外一个接口。主要是对适配对象进行调整,以便适合客户的需求

外观模式:定义一个新的、更简单接口(simpler)来封装多个接口(子系统),以封装子系统实现的变化,减少客户与子系统之间的耦合。

适配器模式和外观模式(head first设计模式——6) - haiziguo - 博客园 (cnblogs.com)

外观模式与适配器模式的比较

  • 外观定义了新的接口,适配器使用旧的接口;
  • 适配器使得两个不一致的接口协同工作,而不是定义一个新的;
  • 外观模式的本意是产生一个轻便的接口,适配器的本意是把现有的接口转换一下;
  • 一个外观接口可能包装了多个现有系统的对象,也可能增加了一些功能,而适配器只是包装了一个对象;
  • 多数情况下,外观是单实例的。

GoF and GRASP

GRASP是一般性的,基础的原则,比较笼统、抽象。GRASP原则是对其他设计模式的归纳。

GoF Design Pattern: 实现GRASP的精神(更加具体的实现方式)

一句话解释,GRASP是抽象的理念,GoF是具体的代码。

PV is the most fundamental principle!!!
Specific GOF patterns are concrete applications of GRASP!!!

Observer 观察者模式

Name: 观察者/发布-订阅

Problem: 不同类型的订阅者对象关注于发布者对象的状态变化或事件,并且想要在发布者产生事件时以自己独特的方式作出反应。此外,发布者想要保持与订阅者的低耦合。如何对此进行设计呢?

Solution: 定义“订阅者”(Subscriber)或“监听器”(Observer)接口。订阅者实现此接口。发布者可以动态注册关注某事件的订阅者,并在事件发生时通知它们。

在这里插入图片描述
什么时候使用观察者模式?

  • 某一个对象的状态发生变化的时候,某些其它的对象需做出相应的改变。
  • 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。

信息推送的2种形式

推模式: 当通知消息来之时,把所有相关信息都通过参数的形式“推给”观察者。

(1)优点

  • 所有信息通过参数传递过来,直接、简单,观察者可以马上进行处理,高效、实时。
  • 观察者与被观察者没有一点联系,两者几乎没有耦合

(2)缺点

  • 所有信息都强迫推给观察者,不管有用与否。
  • 如果想添加一个参数,那就需要修改所有观察者的接口函数。

拉模式: 当通知消息来之时,通知的函数不带任何相关的信息,而是要观察者主动去被观察的对象那里去“拉”信息。 (只起通知作用)

(1)优点

  • 可以主动去取自己感兴趣的信息。
  • 如要添加一个参数,无需修改观察者。

(2)缺点

  • 观察者与被观察者有一定的联系。(Subject与Observer交互变多)

Strategy 策略模式

Problem: 如何设计变化但相关的算法或政策?如何设计才能使这些算法或政策具有可变更的能力?

Solution: 在单独的类中分别定义每种算法/政策/策略,并且使其具有共同接口(封装到一系列策略类里面,作为一个抽象类的子类)。

策略模式的结构图

优缺点

策略模式的主要优点如下。

  1. 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if…else 语句、switch…case 语句。
  2. 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
  3. 策略模式可以提供相同行为的不同实现(多态),客户可以根据不同时间或空间要求选择不同的。
  4. 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法
  5. 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离

其主要缺点如下。

  1. 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
  2. 策略模式造成很多的策略类,增加维护难度

Factory 工厂模式

定义

工厂方法定义了一个创建产品对象的工厂接口,将实际创建工作推迟到子类中

在这里插入图片描述

简单工厂

所有创建对象的逻辑集中到一个核心工厂中,违背了OCP(新增一个产品,都要修改FactoryMethod)和高内聚职责分配(专注做少量的事)

工厂模式

工厂模式是简单工厂的进一步抽象和推广。核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。 这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。(符合OCP和高内聚)

抽象工厂

自己看书理解,有点难理解。

工厂模式的优缺点和适用场景

优点:

  1. 代码结构清晰,有效封装变化。Client只关心产品的接口就可以了,至于具体的实现无需关心。即使变更了具体的实现,对Client来说没有任何影响。
  2. 可扩展性,新产品创建只需要多写一个工厂类(OCP)
  3. 降低耦合度。Client只需要知道产品的抽象类,无须关心其他实现类,解开Client与具体实现的耦合(LoD 迪米特法则)。

缺点:

每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

Command 命令模式

定义

命令模式将一个请求封装成一个对象,将发出请求和执行请求的职责分开。

命令模式的结构图

  1. 抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。
  2. 具体命令类(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
  3. 实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
  4. 调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。

优缺点

优点:

  1. 通过引入中间件(抽象command接口)降低系统的耦合度。
  2. 扩展性良好,增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,满足OCP。
  3. 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
  4. 方便实现 Undo 和 Redo 操作。命令的撤销与恢复。
  5. 可以在现有命令的基础上,增加额外功能。比如日志记录,结合装饰器模式会更加灵活。

缺点:可能产生大量具体的命令类。因为每一个具体操作都需要设计一个具体命令类,这会增加系统的复杂性。

Composite 组合模式

Problem: 如何能够像处理非组合(原子)对象一样,(多态地)处理一组对象或具有组合结构的对象呢?/ 如何处理冲突的定价策略?/ 如何使销售对象(sale)不需要知道是否要处理一个或多个定价策略,而且同时还能够提供一种设计来解决冲突?

Solution: 定义原子类和组合类,让它们去实现相同的接口(Component)

定义

部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。

img

img

优缺点

优点:

  1. 高层模块/Client调用简单。可以一致地处理组合对象和单个对象,而不必关心自己处理的是单个对象还是整个组合结构。
  2. 节点自由增加,满足OCP。

缺点:使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒转原则。违背ICP

DP_OO_Principle

僵硬性 Rigidity

  • 难以更改代码
  • 从管理的角度,拒绝任何的变化成为一种制度

易碎性 Fragility

  • 即使是小小的改动也会导致级联性的后果
  • 代码在意想不到的地方终止

固定性 Immobility

  • 代码纠缠在一起根本不可能重用

黏滞性 Viscosity

  • 宁愿重新编写也不愿意修改

OCP&DIP 回顾

  • 33
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值