[Head First设计模式]山西面馆中的设计模式——装饰者模式html
[Head First设计模式]山西面馆中的设计模式——观察者模式编程
[Head First设计模式]山西面馆中的设计模式——建造者模式设计模式
[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式安全
[Head First设计模式]一我的的平安夜——单例模式框架
[Head First设计模式]抢票中的设计模式——代理模式ide
今天忽然跟朋友谈起设计原则,内心想一想面向对象的设计原则与要素都有哪些?掰掰指头算算能说出几个?作了这么久开发,能有几个能说全的?更别说在项目总去使用了。也许,一些设计原则已经成为习惯,好比单一指责,不用说,你们都懂的。这里也总结一下,但愿之后多看多想多练。函数
一个类,只有一个引发它变化的缘由。应该只有一个职责。每个职责都是变化的一个轴线,若是一个类有一个一上的职责,这些职责就耦合在了一块儿。这回致使脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一块儿,会影响复用性。例如:要实现逻辑和界面的分离。post
什么是职责ui
SRP中,把职责定义为“变化的缘由”。若是你能想到N个动机去改变一个类,那么这个类就具备多于一个的职责。这里说的“变化的缘由”,只有时机发生时才有意义。可能预测到会有多个缘由引发这个类的变化,但这仅仅是预测,并无真的发生,这个类仍可看做具备单一职责,不须要分离职责。url
开放封闭原则是全部面向对象原则的核心。软件设计自己所追求的目标就是封装变化,下降耦合,而开放封闭原则正式对这一目标的最直接体现。其余的设计原则,不少时候是为实现这一目标服务的,例如以Liskov替换原则实现最佳的,正确的继承层次,就能保证不会违反开放封闭原则。
关于开放封闭原则,其核心思想
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。
所以,开放封闭原则主要体如今如下两个方面:
对扩展开放,意味着有新的需求或变化时,能够对现有代码进行扩展,以适应新的状况。
对修改封闭,意味着类一旦设计完成,就能够独立完成其工做,而不要对类进行任何修改。
“需求老是变化的”,“世界上没有一个软件是一成不变的”,这些言论对软件需求是最经典的表白。从中投射出一个关键的意思就是,对于软件设计者来讲,必须在不须要对原有系统进行修改的状况下,实现灵活的系统扩展。而如何作到这一点呢?
只有依赖于抽象。实现开放封闭的核心思想就是对抽象编程,而不是对具体编程,由于抽象相对稳定。让类依赖于固定的抽象,因此对修改就是封闭的;而经过面向对象的继承和多态机制,能够实现对抽象体的继承,经过覆写其方法来改变固有行为,实现新的扩展方法,因此对于扩展是开放的。这是实施开放封闭原则的基本思路,同是这种机制是创建在两个基本的设计原则的基础上,这就是Liskov替换原则和合成/聚合复用原则。
对于违反这一原则的类,必须进行重构来改善,经常使用于实现的设计模式主要有Template Method模式和Strategy模式。而封装变化是实现这一原则的重要手段,将常常发生变化的状态封装为一个类。
其核心思想就是:子类必须可以替换其基类。这一思想体现为对继承机制的约束规范,只有子类可以替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。在父类和子类的具体行为中,必须严格把握继承层次中的关系和特征,将基类替换为子类,程序的行为不会发生任何变化。同时,这一约束反过来则是不成立的,子类能够替换基类,可是基类不必定能替换子类。
Liskov替换原则,主要着眼于对抽象和多态创建在继承的基础上,所以只有遵循Liskov替换原则,才能保证继承复用是可靠的。实现的方法是面向接口编程:将公共部分抽象为基类接口或抽象类,经过继承抽象类或实现接口,在子类中经过覆写父类的方法实现新的方式支持一样的职责。
Liskov替换原则是关于继承机制的设计原则,违反了Liskov替换原则就必然致使违反开放封闭原则。
Liskov替换原则可以保证系统具备良好的拓展性,同是实现基于多态的抽象机制,可以减小代码冗余,避免运行期的类型判别。
所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就下降了客户与实现模块间的耦合。
面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变更时上层也要跟着变更,这就会致使模块的复用性下降并且大大提升了开发的成本。 面向对象的开发很好的解决了这个问题,通常状况下抽象的变化几率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即便实现细节不断变更,只要抽象不变,客户程序就不须要变化。这大大下降了客户程序与实现细节的耦合度。
一个应用中的重要策略决定及业务模型正是在这些高层的模块中。也正是这些模型包含着应用的特性。可是,当这些模块依赖于低层模块时,低层模块的修改将会直接影响到它们,迫使它们也去改变。这种境况是荒谬的。应该是处于高
层的模块去迫使那些低层的模块发生改变。应该是处于高层的模块优先于低层的模块。不管如何高层的模块也不该依赖于低层的模块。并且,咱们想可以复用的是高层的模块。经过子程序库的形式,咱们已经能够很好地复用低层的模块了。当高层的模块依赖于低层的模块时,这些高层模块就很难在不一样的环境中复用。可是,当那些高层模块独立于低层模块时,它们就能很简单地被复用了。这正是位于框架设计的最核心之处的原则。
依赖倒置原则
A.高层次的模块不该该依赖于低层次的模块,他们都应该依赖于抽象。
B.抽象不该该依赖于具体,具体应该依赖于抽象。
使用多个专门的接口比使用单一的总接口要好。
一个类对另一个类的依赖性应当是创建在最小的接口上的。
一个接口表明一个角色,不该当将不一样的角色都交给一个接口。没有关系的接口合并在一块儿,造成一个臃肿的大接口,这是对角色和接口的污染。
“不该该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。”这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,若是强迫用户使用它们不使用的方法,那么这些客户就会面临因为这些不使用的方法的改变所带来的改变。
分离的手段主要有如下两种:
一、委托分离,经过增长一个新的类型来委托客户的请求,隔离客户和接口的直接依赖,可是会增长系统的开销。
二、多重继承分离,经过接口多继承来实现客户的需求,这种方式是较好的。
面向对象的三个基本特征是:封装、继承、多态。
封装
隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读取和修改的访问级别。
封装途径
封装就是将抽象获得的数据和行为(或功能)相结合,造成一个有机的总体,也就是将数据与操做数据的源代码进行有机的结合,造成“类”,其中数据和函数都是类的成员。
封装的目的是加强安全性和简化编程,使用者没必要了解具体的实现细节,而只是要经过外部接口,以特定的访问权限来使用类的成员。
封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(咱们称之为类)。被封装的对象一般被称为抽象数据类型。
封装的意义:
封装的意义在于保护或者防止代码(数据)被咱们无心中破坏。在面向对象程序设计中数据被看做是一个中心的元素而且和使用它的函数结合的很密切,从而保护它不被其它的函数意外的修改。
封装提供了一个有效的途径来保护数据不被意外的破坏。相比咱们将数据(用域来实现)在程序中定义为公用的(public)咱们将它们(fields)定义为私有的(private)在不少方面会更好。私有的数据能够用两种方式来间接的控制。第一种方法,咱们使用传统的存、取方法。第二种方法咱们用属性(property)。
使用属性不只能够控制存取数据的合法性,同时也提供了“读写”、“只读”、“只写”灵活的操做方法。
访问修饰符:
private:只有类自己能存取.
protected:类和派生类能够存取.
internal:只有同一个项目中的类能够存取.
protected Internal:是Protected和Internal的结合.
public:彻底公开.
继承
继承主要实现重用代码,节省开发时间。
1、C#中的继承符合下列规则:
2、new关键字
若是父类中声明了一个没有friend修饰的protected或public方法,子类中也声明了同名的方法。则用new能够隐藏父类中的方法。(不建议使用)
3、base关键字
base 关键字用于从派生类中访问基类的成员:
多态
1、多态:同一操做做用于不一样的对象,能够有不一样的解释,产生不一样的执行结果。在运行时,能够经过指向基类的指针,来调用实现派生类中的方法。
编译时的多态性:
编译时的多态性是经过重载来实现的。对于非虚的成员来讲,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操做。
运行时的多态性:
运行时的多态性就是指直到系统运行时,才根据实际状况决定实现何种操做。C#中,运行时的多态性经过虚成员实现。
编译时的多态性为咱们提供了运行速度快的特色,而运行时的多态性则带来了高度灵活和抽象的特色。
2、实现多态:
3、override关键字:
重写父类中的virtual修饰的方法,实现多态。
参考:
设计原则:百度百科,Head First设计模式
三特征:http://www.cnblogs.com/mountain-mist/articles/1214996.html
这里虽然很基础的东西,在总结的过程当中,一直在思考,本身在项目有没有违反哪一原则?不断思考+不断重构+不断摸索=成长。从网上搜集了一部分,记录在此,方便回顾。