《{企业通用培训}快播科技设计模式培训》由会员分享,可在线阅读,更多相关《{企业通用培训}快播科技设计模式培训(41页珍藏版)》请在金锄头文库上搜索。
1、设计模式,第一讲 设计原则,主讲:林金星,第一章 单一职责原则 第二章 接口隔离原则 第三章 里氏代换原则 第四章 依赖倒转原则 第五章 迪米特法则 第六章 开放封闭原则,你能从电脑设计想到如何进行软件设计吗?,第一章 单一职责原则,定义:应该有且只有一个原因引起类的变化. 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭到意想不到的破坏。,单一职责的好处: 1、类的复杂性降低,实现什么职责都有清晰明确的定义; 2、可读性提高了,复杂性降低了,可读性自然也就提高了; 3、可维护性提高
2、了,可读性提高了,那当然可读性就提高了; 4、变更引起的风险降低,变更是必不可少的,如果一个接口的单一职责做的好,一个接口的修改只对相应的实现类有影响,对其他接口无影响,这对系统的扩展性、维护性都有很大的帮助,class cShape public: virtual cShape(); virtual void Draw() = 0; /*绘制图形*/ virtual double GetArea() = 0; /*获取面积 */ ; class cSquare : public cShape public: void Draw(); double GetArea(); void SetWid
3、th(double dWidth); double GetWidth(); private: double m_dWidth; ;,现在有两个不同的应用程序用到了类cSquare,一个是有关几何计算方面的,另一个是有关图形方面的。对于前者而说,程序从来不需要绘制图形;而对于后者来说,程序也从来不需要计算图形的面积。 在上面这种情况下,我们的设计就违反了单一职责原则。 下面是一个符合单一职责原则的设计。在这个设计中,把原来的类cShape分为两个类:,cGeometricShape和cGraphicalShape,来分别承担几何和图形两方面的职责。同样,分别派生出GGeometricSquare
4、和cGraphicalSquare。,class cGeometricShape public: virtual cGeometricShape(); virtual double GetArea() = 0; ; class GGeometricSquare : public cGeometricShape public: double GetArea(); void SetWidth(double dWidth); double GetWidth(); private: double m_dWidth; ;,class cGraphicalShape public: virtual cGr
5、aphicalShape(); virtual void Draw() = 0; ; class cGraphicalSquare : public cGraphicalShape public: void Draw(); void SetWidth(double dWidth); double GetWidth(); private: double m_dWidth; ;,第二章 接口隔离原则,接口隔离原则表明客户端不应该被强迫实现一些他们不会使用的接口,应该把胖接口中的方法分组,然后用多个接口代替它,每个接口服务于一个子模块。 接口隔离原则是对接口进行规范约束,其包含以下四层含义: 1.
6、接口尽量要小 这是接口隔离原则的核心定义,不出现臃肿的接口。,class IWorker public: virtual void work() = 0; virtual void eat() = 0; ; class Worker :public IWorker public: void work() / .working void eat() /. eating in launch break ;,工厂改进生产后,买进一批机器人,如果机器人也继承IWorker,将会出现接口臃肿的情况。因为机器人不需要实现eat方法。,class IWorkable public: virtual void
7、 work() = 0; ; class IFeedable public: virtual void eat() = 0; ; class Worker :public IWorkable, IFeedable public: void work() / .working void eat() /. eating in launch break ;,class Robot :public IWorkable public: void work() / .working ,但是“小”是有限度的,首先就是不能违反单一职责原则。,class IConnectionManager public: v
8、irtual void dial(char* number) = 0; virtual void huangup() = 0; ; class IDataTransfer public: virtual void chat() = 0; virtual void answer() = 0; ; class Phone private: IConnectionManager,2. 接口要高内聚 什么是高内聚?高内聚就是提高接口、类、模块的处理能力,减少对外的交互。具体到接口隔离原则就是,要求在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时
9、也有利于降低成本。,3. 定制服务 一个系统或系统内的模块之间必然会有耦合,有耦合就要有相互访问的接口,我们设计时就需要为各个访问者(也就客户端)定制服务。我们在做系统设计时也需要考虑对系统之间或模块之间的接口要采用定制服务。采用定制服务就必然有一个要求:只提供访问者需要的方法。,4. 接口设计是有限度的 接口的设计粒度越小,系统越灵活,这是不争的事实。但是,灵活的同时也带来了结构的复杂化,开发难度增加,可维护性降低,这不是一个项目或产品所期望看到的,所以接口设计一定要注意适度,这个“度”如何来判断的呢?根据经验和常识判断,没有一个固化或可测量的标准。,第三章 里氏代换原则,定义:所有引用基类
10、的地方必须能透明地使用其子类的对象。 只有满足以下2个条件的OO设计才可被认为是满足了LSP原则: .不应该在代码中出现if/else之类对子类类型进行判断的条件。以下代码就违反了LSP定义。,if (obj typeof Class1) do something else if (obj typeof Class2) do something else .子类应当可以替换父类并出现在父类能够出现的任何地方,或者说如果我们把代码中使用基类的地方用它的子类所代替,代码还能正常工作,其它行为不会发生变化。,里氏替换原则LSP是使代码符合开闭原则的一个重要保证。同时LSP体现了: . 类的继承原则:
11、如果一个继承类的对象可能会在基类出现的地方出现运行错误,则该子类不应该从该基类继承,或者说,应该重新设计它们之间的关系。 . 动作正确性保证:从另一个侧面上保证了符合LSP设计原则的类的扩展不会给已有的系统引入新的错误。,class Rectangle public: double getHeight() return m_height; void setHeight(double height) m_height = height; double getWidth() return m_width; void setWidth(double width) m_width = width; p
12、rivate: double m_width; double m_height; ;,class Square :public Rectangle public: void setHeight(double height) Rectangle:setHeight(height); Rectangle:setWidth(height); void setWidth(double width) Rectangle:setHeight(width); Rectangle:setWidth(width); ; void main() Square r; r.setWidth(5); r.setHeig
13、ht(4); if (r.getWidth() * r.getHeight() != 20) throw exception!n; ,包含以下四层含义: 1、子类必须完全实现父类的方法; 2、子类可以有自己的特性; 3、覆写或者实现父类的方法时输入的参数可以被放大; 4、覆写或者实现父类的方法时输出的结果可以被缩小;,class IConnectionManager public: virtual IConnectionManager* self() = 0; ; class ConnectionManager:public IConnectionManager public: Connect
14、ionManager* self() return this; ; ; class HTTPConnectionManager:public ConnectionManager public: HTTPConnectionManager* self() coutHTTPConnectionManager return selfn; return this; ; ;,实现好处: 使用里氏替换原则的目的是增强程序的健壮性,版本升级时也可以保持非常好的兼容性,即使增加子类,原有的子类还是可以继续运行,在实际应用中,每个子类对应不同的业务含义,使用父类作为参数,传递不同的子类则可以完成不同的业务逻辑。
15、当然,要使用子类的“个性化”业务逻辑,必须创建子类的对象,不过采用里氏替换原则设计类时,应尽量避免子类的“个性化”。,第四章 依赖倒转原则,定义:高层模块不应该依赖底层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象; 我们现在来看看依赖有几种,依赖也就是耦合,分为下面三种 1.零耦合(Nil Coupling)关系,两个类没有依赖关系,那就是零耦合. 2.具体耦合(Concrete Coupling)关系,两个具体的类之间有依赖关系,那么就是具体耦,合关系,如果一个具体类直接引用另外一个具体类,就会发生这种关系. 3.抽象耦合(Abstract Coupling)关系.这种关系发生在一个具体类和一个抽象类之间,这样就使必须发生关系的类之间保持最大的灵活性.,class QQCar public: void PutIntoGear() std:cout挂档; ; void StepOnAccelerator() std:cout踩油门; void ControlDirection() std:cout打方向; ;,class Person public: Person() m_car = new QQCar(); void drive() m_car-PutIntoGear(); m_car-StepOnAccelerator(); m_car-Contr