敏捷设计书摘


敏捷设计是一个过程,它是一个持续的应用原则、模式以及实践来改进软件的结构和可读性,避免软件腐化的过程。

软件的腐化

  • 僵化性(Rigidity):很难对系统进行改动,因为每个改动都会迫使许多对系统其他部分的其他改动。
  • 脆弱性(Fragility):对系统的改动会导致系统中和改动的地方在概念上无关的许多地方出现问题。
  • 牢固性(Immobility):很难解开系统的纠结,使之成为一些可在其他系统中重用的组件。
  • 粘滞性(Viscosity):做正确的事情比作错误的事情要困难。
  • 不必要的复杂性(Needless Complexity):设计中包含有不具任何直接好处的基础结构。
  • 不必要的重复(Needless Repetition):设计中包含有重复的结构,而该重复的结构本可以使用单一的抽象进行统一。
  • 晦涩性(Opacity):很难阅读、理解。没有很好地表现出意图。

原则

单一职责原则(SRP)

就一个类而言,应该仅有一个引起它变化的原因。在SRP中,我们把职责定义为“变化的原因”。如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。当需求发生改变时,该变化会反映为类的职责的变化。如果一个类承担了多于一个的职责,那么对引起变化的职责的修改,有可能会影响到其他职责的功能。

开放-封闭原则(OCP)

软件实体(类、模块、函数等等)应该是可以扩展的,但不可以修改,它们对于扩展是开放的,对于更改是封闭的。当需求改变时,不应该修改已有的模块的源代码和二进制代码,而是通过扩展模块的功能来满足需求的变更。

实现OCP原则的关键工具是抽象。对于行为容易发生改变的部分,利用抽象体进行连接。模块之间在行为容易改变的地方通过相对固定的抽象体相互连接,利用抽象的多态性实现行为的扩展。

两个例子:

通过抽象体Drawable实现绘制形状,当有新的形状时,paint函数和已有的shape都不需要修改(封闭),只需要增加(扩展)新的形状类。

class Drawable
{
public:
    virtual void Draw() = 0;
}

void Window::paint()
{
    for (Drawable *s : shapes_)
    {
        s->Draw();
    }
}

class Rectangle : public Drawable
{
public:
    void Draw()
    {
        // draw Rectangle
    }
}

class Circle : public Drawable
{
public:
    void Draw()
    {
        // draw Circle
    }
}

为了使得上面例子的paint函数支持绘制形状的顺序性,同时使得顺序性的变化具有可扩展性,需要将顺序变化部分抽象出来以供扩展(开放),并将按照顺序画形状这一行为固化(封闭)。

class Drawable
{
public:
    virtual void Draw() = 0;
    bool operator<(const Drawable &) const = 0;
}

void Window::paint()
{
    vector<Drawable*> ordered_list = shapes_;
    sort(ordered_list.begin(), ordered_list.end());

    for (Drawable *s : ordered_list)
    {
        s->Draw();
    }
}

class Rectangle : public Drawable
{
public:
    void Draw()
    {
        // draw Rectangle
    }
    bool operator<(const Drawable &s) const
    {
        // order
    }
}

class Circle : public Drawable
{
public:
    void Draw()
    {
        // draw Circle
    }
    bool operator<(const Drawable &s) const
    {
        // order
    }
}

Liskov替换原则(LSP)

子类型必须能够替换掉它们的基类型。Liskov原则是使得OCP成为可能的主要原则和保证。子类型对于基类性的替代是一种IS-A的关系,而IS-A并不是概念上的,而应该是行为上的,不能说正方形属于矩形,就一定要让正方形继承自矩形。行为方式才是软件真正关注的问题。

这种行为上的一致,可以用基于契约的设计来指导,比如每个方法对于前置条件、后置条件的约束在子类中都需要得到保证。基于契约的设计常常通过单元测试来检测和实现。

依赖倒置原则(DIP)

  • 高层模块不应该依赖于低层模块。二者都应该依赖于抽象。
  • 抽象不应该依赖于细节。细节应该依赖于抽象。

在层次化的构架设计中,应该由高层次的模块拥有抽象接口,低层次模块实现该抽象接口。这样高层次模块并不知道低层次模块的细节,只是通过抽象接口向低层次模块提出了服务的需求。这和通常的想法有些不同,通常是由低层次的模块设计和拥有对外接口。不反对低层次模块具有调用接口,但是在层次构架中,低层次的模块需要根据高层次模块提出的接口需要,组合自己的功能,实现高层次模块的接口需求。

同时在高层次模块中不应该保存具体的低层次模块的指针或引用,而是应该保存抽象接口的指针或引用。

接口隔离原则(ISP)

不应该强迫客户依赖于他们不用的方法。使用委托或是多重继承等方法,将接口进行分离。当客户在使用一个类时,如果使用的是该类的一个职责,就只将该职责对应的接口提供给客户。如果强迫客户程序依赖于他们不使用的方法,那么这些客户就面临着由于这些未使用方法的改变所带来的变更。

原文地址:https://www.cnblogs.com/songyuncen/p/12076142.html

时间: 2024-11-20 13:50:51

敏捷设计书摘的相关文章

敏捷设计

前言 本系列内容为 Robert C. Martin 敏捷开发一书的读书笔记,前两篇介绍了敏捷开发的一些基本原则和方法,这一篇开始介绍 敏捷设计. 一. 什么是敏捷设计 1. 设计的臭味--腐化软件的气味 ① 僵化性: 很难对系统进行改动,因为每个改动都会迫使许多对系统其他部分的其他改动. ② 脆弱性: 对系统的改动会导致系统中和改动的地方在概念上无关的许多地方出现问题. ③ 牢固性: 很难解开系统的纠结,使之成为一些可在其他系统中重用的组件. ④ 粘滞性: 做正确的事情比做错误的事情要困难.

[敏捷设计]1.什么是敏捷设计

一.设计臭味 1.僵化性 僵化性是指难以对软件进行改动,即使是简单的改动.如果单一的改动会导致有依赖关系的模块中的连锁改动,那么设计就是僵化的.改动时,必须要改动的模块越多,设计就越僵化. 2.脆弱性 脆弱性是指,在进行一个改动时,可能会导致程序的许多地方出现问题.常常是,出现新问题的地方与改动的地方没有概念上的关联. 3.顽固性 顽固性是指,设计中包含了对其他系统有用的部分,但是要把这些部分从系统中分离出来所需要的代价很巨大的. 4.粘滞性 软件粘滞性 当面临一个改动时,开发人员常常发现会有多

[敏捷设计]3.OCP开放封闭原则

一.定义 软件实体(类.模块.函数等)应该是可以扩展的,但是不可修改. 如果正确的应用了OCP原则,那么 以后在进行同样的改动时,就只需要添加新的代码,不必修改已经正常运行的代码. 二.OCP概述 1.对于扩展是开放的 这意味着模块的行为是可以扩展的.当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为.换句话说,我们可以改变模块的功能. 2.对于修改是封闭的 对模块进行扩展时,不必改动模块的源代码或者二进制代码. 3.有何问题 这两个特征好像是互相矛盾的.扩展模块行为的通常

[敏捷设计]5.DIP依赖倒置原则

一.定义 1.高层模块不应该依赖低层模块,二者都应该依赖抽象 2.抽象不应该依赖于细节.细节应该依赖于抽象 二.层次化 1.简单介绍 结构良好的面向对象架构都具有清晰的层次定义,每个层次通过一个定义良好的.受控的接口向外提供了一组内聚的服务. 对于这个陈述的简单理解可能会致使设计者设计出类似下图的结构. 图中,高层的Policy层使用了低层的Mechanism层,而Mechanism层又使用了更细节的Utility层.这样,Policy层对下面的Utility层的改动都是敏感的. 这种依赖关系是

[敏捷设计]2.SRC单一职责原则

一.定义 一个类应该只有一个发生变化的原因. 二.为什么要使用SRC 因为每一个职责都是变化的一个轴线.当需求变化时,这种变化就会反映为类的职责的变化.如果一个类承担了多于一个的职责,那么引起它变化的原因就会有多个. 如果一个类承担的职责过多,就等于把这些职责耦合在了一起.一个职责的变化可能会消弱或抑制这个类完成其他职责的能力.这种耦合会导致脆弱的设计,当变化发生时,设计会遭到意想不到的破坏. 三.案例演示 考虑图中的设计. Rectangle类具有两个方法,一个方法把矩形绘制到屏幕上,另一个方

[敏捷设计]4.Liskov替换原则

一.定义 子类型必须能替换掉它们的基类型 二.提取公共部分的方法代替继承 如果一组类都支持一个公共的职责,那么它们应该从一个公共的超类继承该职责. 如果公共的超类不存在,那么就创建一个,并把公共的职责放入其中.毕竟,这样一个类的有用性是确定无疑的. 然而稍后对系统的扩展也许会假如一个新的子类,该子类很可能会以新的方式来支持同样的职责.此时,这个新创建的超类可能会会是一个抽象类. 三.结论 LSP是使OCP成为可能的主要原则之一.正是子类型的可替换性才能使得使用基类型表示的模块在无需修改的情况下就

《敏捷软件开发读书笔记之一》

要想成为一名优秀的软件开发者,需要熟练应用编程语言和开发工具,更重要的是能够领悟代美代码背后的原则和前人总结的经验——这正是本书的主题.本书凝聚了世界级软件开发大师RobertCMartin数十年软件开发和培训经验,不仅是一部深入浅出.生动易懂的面向对象原则与模式著作,而且还是一部通俗的敏捷方法导引书和快速实用UML教程.分为敏捷开发,敏捷设计,薪水支付案例研究,打包薪水支付系统,气象站案例研究和ETS案例研究六个部分,包含30个章节.以下是我对前两个部分的认识及见解: 以下六章是对第一部分敏捷

敏捷开发综述

我看的书是<敏捷软件开发:原则.模式与实践>是2003 年9月清华大学出版社出版的图书. 原书名: Agile Software Development: Principles, Patterns, and Practices 这本书的重要内容: ●讲述在预算和时间要求下,软件开发人员和项目经理如何使用敏捷开发完成项目. ●使用真实案例讲解如何用极限编程来设计.测试.量构和结对编程 ●包含了极具价值的可多次使用的c++和java源代码. ●重点讲述了如何使用uml和设计模式解决面向客户系统 如

UI产品设计流程中的14个要点

http://www.sj33.cn/digital/wyll/201404/38318.html 自从我在 Dribbble 上贴了一幅我的产品设计成果,受到了大家伙热烈的反馈,对此我深受鼓励,我决定写下这篇文章,用来记录我这两年里作为产品设计师,所学到的东西.说起来有点惭愧,这几年我一直都在使用同一套产品设计的流程,但是我觉得这套流程最适合我,对我来说是最理想的,所以就很少去更换.我的这套工作流程我觉得有 4 个地方可以和大家分享一下--前期工作.具体设计.后期工作以及一些提高效率的小细节