设计模式——设计模式原则

“一腔诗意喂了狗,不如代码三两行”

1、单一职责原则(SRP): SingleResponsibility Principle

“有且仅用一个原因引起类的变更”

1)首先自然有一个问题,所谓的单一职责具体是怎么样span>

原则的定义是:有且仅有一个原因引起类的变更。在此之前首先我觉得弄清楚有哪些东西会引起类的变更,对此有一些自己的理解。

举一个例子,在设计类的时候,会将业务对象(Bussiness Object)和业务逻辑(Bussiness Logic)分离。实际上此时就是用了单一原则,BO负责修改对象的属性,Biz则负责处理对象的行为,各自只负责一件事

在一定程度上,这个会增加类的复杂性,但是个人觉得SRP的最终结果是,当一个原因发生变化时,对整个系统的影响在此时最小,仅需要做最少的改动,就可以使系统在新的场景下正常运行。考虑到软件设计中常用继承以及其它的OOP模式,在这种情况下,不会出现一个类的变更,导致与它有关的类都必须被修改。

2)第二个问题是如何划分职责并以此设计类

暂无一个具体的思路。按照一些经验,能得到一些共性,比方说各种设计模式。

 

2、里氏替换原则(LSP):LiskovSubstitution Principle

“只要父类能出现的地方子类就可以出现,而且替换成子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是反过来则不行”

1)子类必须完全实现父类的方法:

classPen

{

public:

Pen(stringt):penType(t)

{}

virtualvoid Write() = 0;

private:

stringpenType;

};

 

 

classRedPen:public Pen

{

public:

RedPen():Pen(string(“redpen”))

{

 

}

 

voidWrite()

{

cout

}

};

 

 

 

classBlackPen :public Pen

{

public:

BlackPen():Pen(string(“red pen”))

{

 

}

 

voidWrite()

{

cout

}

};

 

一个不太恰当的例子,RedPenBlackPen都继承了Pen且各自实现Penwrite方法,所以你只要拿到笔,不管是什么笔尽管写

2)子类可以有自己的个性:子类可以有自己的属性和方法

3)覆盖或实现父类方法时输入参数可以被放大:仔细想一下就可以知道这是必然的,因为父类出现的地方子类也可以出现,父类接收到的参数子类也必须可以接受,那么范围自然子类大于父类

4)覆写或实现父类方法时输出结果可以被缩小:个人觉得仍是父类使用的地方可以被子类代替,包括使用父类方法的返回值的时候。

 

3、依赖倒置原则(DIP):Dependence Inversion Principle

“通过抽象(接口或接口类)使各个类或模块的实现彼此独立,不相互影响,实现模块间的松耦合”

倒置:根据系统设计的需要产生了抽象间的依赖,代替了传统思维中的事物间的依赖

1)面向接口编程:其实是面向抽象编程,接口不负责具体实现,但是具体实现依赖于接口,从高层上使用接口来完成业务逻辑,而底层仅仅负责实现,即使改动的话,也只需要对高层进行逻辑上的修改(此时高层完全是抽象的,与具体的实现没有关系),即使修改了的话,对系统的影响也不会向下传递。感觉是:如果出现了新的需求,系统只需要在逻辑上进行一定的修改就可以完全适应新的需求(这里的逻辑指的是与需求相关的逻辑,比如出现了新的对象,而接口本身是不变的,不知道这样说对不对QAQ

2)关于松紧耦合:

紧耦合,定义上是指系统易变,出现了一点新需求就得大改特改,紧耦合与依赖关联很大,如果依赖是具体的实现类,那么很大程度上会存在这种关系,由于依赖了实现类,那么传入参数的范围随之缩小到了实现类这个层面(底层模块),因此便不能兼容更多。

松耦合:传入的接口而言不应该是具体的类,而应该是抽象类,即实现类之间不发生直接的依赖关系,高层模块直接使用抽象类完成业务逻辑,低层模块完成对接口方法的实现,由于使用的是抽象类,通过继承覆盖,修改起来很简单。

3)高层模块与低层模块之间的依赖关系:高层业务逻辑对低层模块的依赖都建立在抽象上),简而言之高层模块使用抽象完成业务逻辑,底层模块实现抽象,Over

 

栗子:

classWriteMan

{

public:

WriteMan(Pen* pen_t) :myPen(pen_t)

{}

 

voidsetPen(Pen * pen_t)

{

myPen= pen_t;

}

 

voidManWrite()

{

cout

myPen->Write();

 

}

private:

Pen* myPen;

};

 

intmain(void)

{

Pen* pen = new RedPen();

WriteManman(pen);

man.ManWrite();

 

pen= new BlackPen();

man.setPen(pen);

man.ManWrite();

 

 

return0;

}

 

//由与WriteMan使用的是一个抽象类Pen所以只要子类实现了Write方法,不管你是什么笔,怎么加,要怎么写(相当于该需求),加一个继承Pen的新类,改一下main函数就可以了

4)依赖关系的传递:通过构造函数传递;通过专门的set函数;通过接口声明依赖对象

 

4、接口隔离原则(ISP):Interface Segregation Principle

“类间的依赖关系应该建立在最小的接口上”

1)建立单一接口:接口尽量细化,尽量使用专门的接口(提供给几个模块就应该有几个接口)。

2)接口尽量小:不出现臃肿的接口,但是接口也不能违反单一职责原则,不过分细分

3)接口高内聚:接口中尽量少公布public方法

4)定制服务:只提供访问者需要的方法,必要时对接口进行拆分

 

 

5、最少知识原则(LKP):Least Knowledge Principle

“一个类应该对自己需要耦合或调用的类知道得最少”

1)朋友类:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于成员朋友类。而一个类只和朋友类交流!

2)朋友类之间应当低耦合:尽量少的暴露public方法,通过相互之间职责的转移以及封装,完全可以通过安装的方式将一个类中依赖朋友类过多方法的实现交由朋友类来替它实现,同时朋友类可以对原来的一些public方法进行封装,使暴露的public方法减少

高内聚,低耦合

 

6、开闭原则(OCP):Open Closed Principle

“一个软件实体如类、模板和函数应该对扩展开放,对修改关闭”

一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码,已有的代码已经是测试正确的,在一个好的系统结构下,尽量不要动已经确定是无误的东西,而是通过添砖加瓦来完成扩展以适应变化,同时这样可以是之后的测试量变小,只需测试新添的那部分即可

1)抽象约束:通过接口或是抽象类可以约束一组可能的变化,并且能够实现对扩展开放。包含三层含义:第一,通过接口或是抽象类约束扩展,对扩展边界进行限定,不允许出现在接口或抽象类中不存在的public方法;第二,参数类型、引用对象尽量使用接口或是抽象类,而不是实现类;第三,抽象层尽量保持稳定,一旦确定即不允许修改。(可以参照上面的依赖倒置原则来看看)

 

简而言之:写好了的别动,加东西就行

 

 

以上内容参照《设计模式之禅》,加由自己的一些理解形成

 

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2018年6月6日
下一篇 2018年6月6日

相关推荐