刚接触代码的时候是因为Unity,因为Unity支持C#编写所以就学习了解了一下C#,在刚接触的时候,对设计模式很是头疼,什么面向对象的设计原则,还有各种模式,真的是劝退初学者。虽然现在工作上大多用轻量级的Lua,但还是向重新拾一下C#,所以写此博客来学习一下C#编程的设计模式。
接下来开始正题
这里附上设计模式导览。想直接了解的可以点击直接去看设计模式。
学习设计模式首先要弄懂设计模式是什么,为什么要存在设计模式。
GoF整合的编程前辈的编码习惯就是设计模式。GoF(Gang of Four)就是有四个有梦想有组织有纪律的大佬,这四个人觉得编程迟早会火,那么大家就不能各写各的啊,别说一起开发了,读别人的代码都得半天,于是就整理了一下编程的格式,弄了本书就叫设计模式。这才有了后来的各种设计模式。
知道了是什么后其实也就应该理解为什么了,大家好互相工作呗。学好设计模式,方便你我他。也就是说,设计模式的存在就像是普通话,如果你身边的人够了解你的编程模式或者说你就敲代码给自己看,那么你完全没有必要整这玩意。
(可维护性,可复用性。目标就这两点)
既然设计模式的存在就是为了融入集体,那么怎么融入呢,敲得和大家的一样就行了嘛,在这里GoF为我们确立了一下代码的好坏之分,到底是不是这四个人确立的咱们不去深究,深究一下代码的评分准则
相比看设计原则的程序员都了解有面向对象的概念,但真的深究到底什么是面向对象大家的答案五花八门,在此谈一下本人对这个概念的理解:想要了解面向对象,学一下C语言就可以了。这就是我的理解,面向对象就是一个相对于面向过程的概念,相辅相成。
如果你真的不想先了解一下C语言,那你你只要记住,面向对象设计的两个目标:软件的可维护性,可复用性。
可维护性:指软件能够被理解,改正,适应及扩展的难易程度。
可复用性:值软件能够被重复使用的难易程度。
可以理解为你再编程领域深造的目标就是这两点。现在可以拿笔把这两点刻在电脑
旁边。
解决了面向对象这个千古难题后(如果不理解没有关系,继续看就完事,代码敲多了,坑跳多了自然就了解了),聊一下设计原则这个万古难题,设计原则,就是为了评判可维护性和可复用性的标准。
1.单一职责
定义:一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。
看起来很好理解,对于这种看起来很好理解的定义其实往往才是坑最大的定义。首先来看一下职责这个东西,定义中说到了只包含单一的职责,你可能读懂了,但我要是问你职责这个东西是什么意思你可能会骂我智障。但是你真的懂职责到底是什么吗。这个时候就要各梳己见了,我只记录我自己的想法:
己见:职责就是一个一个脚本在干什么。脚本的概念在Unity中很好理解,在c#中则理解为一个方法,该干什么(更深一点的理解就是静态方法该干什么,因为非静态方法大多数用来表示对象的行为操作)。单一职责最大的难点就体现在如何控制类的粒度大小,这就要靠经验了。
2.开闭原则
(面向对象的设计目标)
定义:软件实体应当对扩展开放,对修改关闭。
通俗易懂,可修不可改。那么咱们再来抬个杠,对所有的修改都关闭?那岂不是我写了代码就不能改了,只添加??如果有人说“没错就是不能该只能添加”,那你去把GoF叫来看他们的代码改不改。
己见:不能修改的部分是逻辑类中的方法,因为一个项目的复杂度大多体现在逻辑类中,尽量少的甚至不能去修改逻辑类中的代码,实现在逻辑类中只能加不能改才是真正的开闭原则。至于哪些是逻辑类等写到第一个设计模式时会提醒。
3.李氏替换原则
顾名思义,一个姓李的发表的原则,这里给大家科普一下,李氏原则是以Barbara Liskov教授的姓氏命名,音译中文名字叫 芭芭拉·利斯科夫 读到芭芭拉那说实话我真的笑了,抱歉。这个教授时美国第一位计算机科学女博士,大佬大佬。
定义:如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都替换o2时,程序P的行为没有变化,那么类型S是类型T的子类型。
通俗易懂(个屁),虽然我会码上通俗版的定义,但我还是建议大家读懂上面的定义,画下图可以帮助理解。
通俗定义:所有引用基类的地方必须能透明地使用其子类的对象。
又是一个看起来很好理解的定义,但是啥叫透明啊。
己见:虽然我也没有找到官方的解释,但从个人经验来说,透明的使用就是直接使用。对与李氏替换原则举一个基本上所有人都会举的例子:我喜欢动物,那我一定喜欢狗,我喜欢狗,但我不一定喜欢所有动物。这也就是为什么我推荐大家读第一个比较难理解的定义了,那个定义就是这个意思。在程序中尽量使用基类类型对对象进行定义,而在运行时再确定其子类类型。从另一层面理解来说就是尽量让父类都是抽象类或者是接口,很大程度上提高了代码的复用性。也就有那么一点面向接口编程的意思。
4依赖倒置原则
(面向对象设计的主要实现机制之一)
定义:高层模块不应该依赖底层模块,它们都应该依赖抽象。抽象不应该依赖细节,细节应该依赖于抽象。
这里提到了依赖的关系,既然扯到了类与类间的关系,那就简单来说一下吧。
依赖,关联,泛化,实现
这里我只说一下我对这四个概念的简单理解。
依赖:就是引用,一个类中的方法有其他类型的参数就是依赖于另一个类。是类与类中耦合度最小的关系。
关联:是一种引用关系,可以初步理解为实例。耦合度第二高。
泛化和实现:同为继承关系,泛化是正儿八经的继承,实现是继承接口并实现。耦合度最高。
己见:了解了类与类间的关系后,我们再来看定义,高层不应该以来底层模块,换句话说就是高层不能引用底层,也就是父类不能引用子类。其实除了最后半句话来说都是在解释最后的半句话。细节应该依赖于抽象,就是在强调针对接口编程,不要针对实现编程。当然就是为了提高复用性,因为接口灵活啊。
所以说,开闭原则是目标,李氏代换原则是基础,依赖倒置原则是手段。
就是通过面向接口编程来实现可加不可改的代码。
5.接口隔离原则
定义:客户端不应该依赖那些它不需要的接口。
还是一条看起来很好懂的定义。”不就是说要少继承接口吗“你要是这么想那就错怪这个原则了。这里的接口往往有两种不同的含义:一种是指一个类所具有方法特征的集合,也就是单一职责中这个类的职责,这仅仅是一种逻辑上的抽象;另一种是指语言中的接口,也就是interface声明的类。所以说这个定义本身就有两重定义:
1.角色隔离原则(类的Interface接口要按职责划分,达到逻辑上的完全满足)
2.接口隔离原则(Interface接口要尽量的小,不要什么功能都有,也就是对客户端隐藏那些他们不需要的行为)
己见:用好接口隔离原则说实话很难,因为首先要有架构思想才能考虑的很周到,接口粒度的大小很难把控,初学者还是尽量粒度往小了写,也就是尽量夺得写接口,虽然很麻烦,但最起码满足了类的单一职责。
6.迪米特法则
来自于1987年美国东北大学(Northeastern University)的一个名为”Demeter“的项目。(东北大学,不好意思我又笑了一下,抱歉)
定义:每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
定义中很模糊的一个概念就是密切相欢的软件单位,到底什么才算是密切相关?在此介绍一下迪米特法则的另外几种定义形式:”Don’t talk to strangers"(不要和陌生人说话模式),”Talk only to your immediate friends“(只与你的直接朋友通信),所以在迪米特法则中,对于一个对象,其朋友包括以下几类:
1)当前对象本身,
2)以参数形式传入到当前对象方法中的对象。
3)当前对象的成员对象。
4)如果当前对象的成员对象是一个集合,那么解后中的元素也是朋友。
5)当前对象所创建的对象。
己见:该法则的一切规定都是在耦合的基础上降低耦合。低耦合间接程度上就提高了代码的复用性,也能更好地维护开闭原则。
设计模式,就是在一定程度上按照设计原则去书写代码,而设计原则又是在最大程度的限制代码的可复用性与可维护性尽可能地高。也就是所有的设计模式其目的是一样的的,就是最开始提到的可复用性与可维护性。
从下篇开始与大家一起学习23种设计模式
参考书籍:《C#设计模式》(第二版)刘伟 胡志刚 编著 清华大学出版社