软件设计的五大原则.ppt
《软件设计的五大原则.ppt》由会员分享,可在线阅读,更多相关《软件设计的五大原则.ppt(51页珍藏版)》请在三一办公上搜索。
1、软件设计中的5大原则,1.单一职责原则(SRP),陈述:就一个类而言,应该只有一个导致其变化的原因分析:一个职责就是一个变化的轴线一个类如果承担的职责过多,就等于将这些职责耦合在一起。一个职责的变化可能会虚弱或者抑止这个类完成其它职责的能力多职责将导致脆弱性的臭味,Rectangle类具有两个职责:计算矩形面积的数学模型将矩形在一个图形设备上描述出来,示例1:,Rectangle类违反了SRP,具有两个职能计算面积和绘制矩形这种对SRP的违反将导致两个方面的问题:包含不必要的代码一个应用可能希望使用Retangle类计算矩形的面积,但是却被迫将绘制矩形相关的代码也包含进来一些逻辑上毫无关联的原
2、因可能导致应用失败如果GraphicalApplication的需求发生了变化,从而对Rectangle类进行了修改。但是这样的变化居然会要求我们重新构建、测试以及部署ComputationalGeometryApplication,否则其将莫名其妙的失败。,修改后的设计如下:,Modem类(可能)有两个职责:拨号通信,示例2:一个Modem的接口:Class Modempublic:virtual void dail(char*pno)=0;virtual void hangup()=0;virtual void send(char c)=0;virtual void recv()=0;,什
3、么是职责?职责是“变化的原因”。上面的例子可能存在两种变化的方式:连接和通信可能独立变化在这种情况下,应该将职责分开。例如,应用的变化导致了连接部分方法的签名(signature)发生了变化,那么使用数据连接的部分也需要重新编译、部署,这会相当麻烦,使得设计僵化。连接和通信同时变化这种情况下,不必将职责分开。反而分离可能导致“不必要的复杂性”的臭味,刻舟求剑是错误的。王亚沙,修改后的设计如下:,有一点需要注意:在ModemImplementation中实际还是集合了两个职责。这是我们不希望的,但是有时候却是必须的。但是我们注意到,对于应用的其它部分,通过接口的分离我们已经实现了职责的分离。Mo
4、demImplementation已经不被其它任何程序所依赖。除了main以外,其他所有程序都不需要知道这个函数的存在。,常见错误提醒:持久化与业务规则的耦合。例如:,业务规则经常变化,而持久化方法却一般不变。将这两个职责耦合在一起,将导致每次因为业务规则变化调整Employee类时,所有持久化部分的代码也要跟着变化,2.开放封闭原则(OCP),陈述:软件实体(类、模块、函数等)应该是可以扩展的,同时还可以是不必修改的,更确切的说,函数实体应该:(1)对扩展是开放的当应用的需求变化时,我们可以对模块进行扩展,使其具有满足改变的新的行为即,我们可以改变模块的功能(2)对更改是封闭的对模块进行扩展
5、时,不必改动已有的源代码或二进制代码。分析:世界是变化的(而且变化很快),软件是对现实的抽象软件必须能够扩展如果任何修改都需要改变已经存在的代码,那么可能导致牵一发动全身现象,进而导致雪崩效应,使软件质量显著下降,实现OCP的关键是抽象:例子1,class clientserver,class serverint serverData;public:void ServerFunc();,例子1(续)这个程序出了什么问题?,client和server都是具体类,接口与实现没有实现分离。如果我们想要让client调用一个新的server类,那么我们不得不修改client的源代码从而带来编译、链接、
6、部署等一系列的问题。,见下页程序,2.开放封闭原则(OCP),例子1(续),class clientserver,class serverint serverData;public:void ServerFunc();,class server1int serverData;public:void ServerFunc();,class clientserver1,2.开放封闭原则(OCP),例子1(续)修改后的设计,class clientClientInterface,class ClientInterfacevirtual void ServerFunc()=0;class server
7、:public ClientInterfaceint serverData;public:void ServerFunc();,例子1(续)一个问题:为什么上述的ClientInterface这个类要取这么个名字,叫做AbastractServer岂不更好?其实这里面蕴含了一个思想:client类中更多的描述了高层的策略,而Server类中是对这些策略的一种具体实现。而接口是策略的一个组成部分,他根client端的关系更加密切我们应该这样想问题:ClientInterface中定义了client期 望Server做什么,而server具体类是对client这种要求的 一种具体实现。OCP原则其
8、实是要求我们清晰的区分策略和策略的具体实现形式。允许 扩展具体的实现形式(开放),同时将这种扩展与策略隔离开来,使 其对上层的策略透明(封闭)。,例子2C语言程序,-shape.h-emum ShapeTypecircle,square;struct ShapeShapeType itsType;-circle.h-struct CircleShapeType itsType;double itsRadius;CPoint itscenter;-square.h-struct SquareShapeType itsType;double itsSide;CPoint itsTopLeft;,-
9、drawAllShapes.cpp-typedef struct Shape*ShapePointer;void DrawAllShapes(ShapePointer list,int n)int i;for(i=0;iitsType)case square:s-Square();break;case circle:s-DrawCircle();break;,例子2(续)批判这个程序不符合OCP,如果需要处理的几何图形中再加入“三角形”将引发大量的修改僵化的增加Triangle会导致Shape、Square、Circle以及DrawAllShapes的重新编译和部署脆弱的因为存在大量的既难以查
10、找又难以理解的Switch和If语句,修改稍有不慎,程序就会莫明其妙的出错牢固的想在一个程序中复用DrawAllShapes,都必须带上Circle、Square,即使那个程序不需要他们,例子2(续)修改后的设计,class Shapepublic:virtual void Draw()const=0;class Square:public Shapepublic:virtual void Draw()const;class Circle:public Shapepublic:virtual void Draw()const;,void DrawAllShapes(Vector,例子2(续)再
11、看这些批判再加入“三角形”将变得十分简单:僵化的增加Triangle会导致Shape、Square、Circle以及DrawAllShapes的重新编译和部署脆弱的因为存在大量的既难以查找又难以理解的Switch和If语句,修改稍有不慎,程序就会莫明其妙的出错牢固的想在一个程序中复用DrawAllShapes,都必须带上Circle、Square,即使那个程序不需要他们,谎言:上述代码并不完全封闭“如果我们希望正方形在所有圆之前绘制”会怎么样?对绘图的顺序无法实现封闭更糟糕的是,刚才的设计反而成为了实现“正方形在所有圆之前绘制”功能的障碍。,真实的谎言:一般而言,无论模块多么“封闭”,都会存在
12、一些无法对之封闭的变化没有对所有变化的情况都封闭的模型我们怎么办?既然不可能完全封闭,我们必须有策略的对待此问题对模型应该封闭那类变化作出选择,封闭最可能出现的变化 这需要对领域的了解,丰富的经验和常识错误的判断反而不美,因为OCP需要额外的开销(增加复杂度)敏捷的思想我们预测他们,但是直到我们发现他们才行动,回到例2:要实现对排序的封闭应该如何设计?,class Shapepublic:virtual void Draw()const=0;virtual bool Precedes(const Shape,对于各个Shape的派生类,需要实现具体的排序规则Circle类的排序规则实现如下:B
13、ool Circle:Precedes(const Shape这个程序符合OCP吗?,利用“数据驱动”的方法获得封闭性,#include#include#include using namespace std;class Shapepublic:virtual void Draw()const=0;virtual bool Precedes(const Shape,bool Shape:Precedes(const Shape,通过上述方法,我们成功地做到了一般情况下DrawAllShapes函数对于顺序问题的封闭,也使得每个Shape派生类对于新的Shape派生类的创建者或者给予类型的Sha
14、pe对象排序规则的改变是封闭的。对于不同的Shapes的绘制顺序的变化不封闭的唯一部分就是表本身。可以把表放置在一个单独的模块中,和所有其他模块隔离,因此对于表的改动不会影响其他任何模块。事实上在C中我们可以在链接时选择要使用的表。,3.LisKov替换原则(LSP),陈述:子类型(Subtype)必须能够替换他们的基类型(Basetype)Barbara Liskov对原则的陈述:若对每个类型S的对象o1,都存在一个类型T的对象o2,使得在所有针对T编写的程序P中,用o1替换o2后,程序P的行为功能不变,则S是T的子类型。分析:违法这个职责将导致程序的脆弱性和对OCP的违反例如:基类Base
15、,派生类Derived,派生类实例d,函数f(Base*p);f(&d)会导致错误显然D对于f是脆弱的。如果我们试图编写一些测试,以保证把d传给f时可以使f具有正确的行为。那么这个测试违反了OCP因为f无法对Base的所有派生类都是封闭的,示例1:,struct Pointdouble x,y;struct shapeenum ShapeTypesquare,circle itsType;shape(ShapeType t):itsType(t);struct Circle:public ShapeCircle():Shape(circle);void Draw()const;Point it
16、sCenter;double itsRadius;struct Square:public ShapeSquare():Shape(square);void Draw()const;Point itsTopLeft;double itsSide;,void DrawShape(const Shape,显然,DrawShape违反了OCP,为什么?因为Circle和Square违反了LSP,示例2:一次更加奇妙的违规,class RectanglePoint topLeft;doulbe width;double height;public:void setWidth(double w)widt
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 软件设计 原则

链接地址:https://www.31ppt.com/p-6206978.html