无废话c设计模式.docx
- 文档编号:10787440
- 上传时间:2023-02-22
- 格式:DOCX
- 页数:32
- 大小:43.90KB
无废话c设计模式.docx
《无废话c设计模式.docx》由会员分享,可在线阅读,更多相关《无废话c设计模式.docx(32页珍藏版)》请在冰豆网上搜索。
无废话c设计模式
无废话C#设计模式之一:
开篇
什么是设计模式?
什么是少林拳呢?
少林拳是少林僧人经过长期的总结,得出的一套武功套路。
有一本叫做少林拳法的武功秘籍,上面记载这这套拳法的适用人群,打法套路和学成后的效果。
设计模式虽然记录在了设计模式一书上,但是要真正掌握设计模式光靠看每一个模式的结构并且进行模仿是不够的。
试想一下,在真枪实战的情况下,谁会和你按照少林拳法,一二三四的套路打呢?
打套路也只能用来看看,只有当你能根据不同的场景灵活出招的时候才能说是学会了这套拳法。
相似的例子还有三十六计,这也是一种模式,每种计谋都是针对不同场景的,如果不管遇到什么时候都来个“走为上”,那这仗还怎么打呢?
总之,设计模式要用活才能发挥作用。
设计模式有什么用?
设计模式可以让你在遇到需求变化的时候不至于手忙脚乱。
设计模式可以让你程序的可维护性、可扩展性更好。
设计模式可以让程序的性能更高。
当然,这些的前提是正确使用了设计模式,如果滥用的话那么设计模式可以让程序没人看得懂,让程序速度慢到死,让程序不能维护,添加新的功能等于重做。
设计模式的原则?
● 单一职责:
你不希望因为电脑内存损坏而更换CPU吧,同样也不应该让一个类有多种修改的理由。
● 对扩展开放,对修改封闭:
你一定不希望电脑只有一个内存槽,加内存就要换主板吧,程序也应该能在不修改原先程序的情况下就能扩展功能。
● 里氏替换:
如果你买的DX9显卡不支持DX9特性,那么这个显卡一定没法用。
如果父类的方法在子类中没有实现那就晕了。
在程序的世界中千万别认为鸟都会飞,先考虑清楚将会有哪些鸟吧。
● 依赖倒置:
针对接口编程,这样即使实现有变也不需要修改外部代码。
其实,现在电脑的硬件、网络通讯等都是符合这个原则的,比如USB接口、PCI-E接口、TCP/IP协议。
● 接口隔离:
花3000买一个带拍照、听MP3功能的手机还是花1000买一个手机、1000买一个MP3、1000买一个数码相机呢?
买了前者的话手机动不动就要修,而且还不一定是因为不能打电话而修,买了后面三样的话即使修也不影响其它使用,你说买哪个?
记得看过一个例子很恰当,说是修电脑比修收音机简单多了。
电脑坏了,更换一个零件即可,原因是电脑中的各部分都是基于相对稳定的接口,而且部件各司其职,不会相互影响,电脑本身就是一个非常符合设计原则的产品。
收音机的修理没有这么简单了,没有什么部件是插件式的,会修收音机的人肯定明白其中每一个部件的原理。
小程序就好像收音机,确实可以这么做,一共才一个人做的,即使重新做也用不了多少时间。
几十个人的大项目如果要改一个需求需要牵涉所有人来修改,那么这个项目用不了多少时间就会因为维护成本太大,维护后BUG太多而报废。
怎样学习设计模式?
学习新概念英文要什么基础?
首先,要知道26个字母吧。
如果你对面向对象完全没有概念的话,建议先可以看一下面向对象的一些知识。
毕竟,设计模式是面向对象编程模式的一种总结。
学了26个字母你就可以学习新概念了,但是,为了能更好地学习最好是先学一下国际音标。
对于设计模式的学习来说,你可以学习一下UML的一些知识。
当然,完全不知道UML也可以学习设计模式,在学习的过程中慢慢也就会UML了。
设计模式不是什么很高深的东西,有了这些知识大胆地学习吧。
很多人说,看了很多设计模式的文章,为什么就是看不懂呢?
我觉得原因可能有两个,第一就是你没有花时间认真看,第二就是看的文章不适合作为切入点。
不管学习什么,切入点非常重要,如果切入点不是那么平易近人的话很可能会把你拒之门外,对于初学者来说从实例切入最合适。
最好是能碰到自己做过的项目的实例作为切入点,这样你一比较就知道为什么设计模式好了。
如果要把设计模式的学习境界分一下级的话,我这么分:
● 第一重:
能看懂设计模式的文章
● 第二重:
能自己写一个设计模式的骨架
● 第三重:
能自己编一个新的运用设计模式的例子
● 第四重:
能在写代码的时候想到似乎有设计模式适合,在翻阅资料后找到了这种设计模式
● 第五重:
在理解项目的需求后就能意识到哪里可以使用哪种设计模式进行优化
● 第六重:
完全掌握了设计模式的精髓,灵活使用各种设计模式以及其变种
不管怎么样,多看多做多替换才是学习的办法,别人举例十个都不及自己做一个例子,被动十个原则都不及自己体会出一个原则。
每一种设计模式虽然都有一个骨架,但是也不必过于强调这个形式,很多时候根据自己的需求简化一点,改变一点,或者混杂一些其它的设计模式,只要能实现目的了,也是一个不错的选择。
很多人会觉得这么多种设计模式没有几种能用得上。
我觉得这不是什么问题,用不上那就用不上,这些设计模式是大师经历无数大型项目后的精华,如果能在自己做的一个小项目中用上两三个就很不错了,用上二三十个的项目绝对是怪胎。
用不上千万别强求,否则既不利于项目的可维护性又增加了工作量。
还有很多人会觉得这些设计模式很多都是相似的。
而且每个人的感觉还不一样,有人觉得A和B很相似,有人却觉得A和B很好区分,但是B和C却很相似啊。
感觉很好区分,说明你看准设计模式的着重点的,感觉一样说明你看到的还是它的形。
双胞胎虽然形一样,但是神肯定不一样的,只要认准设计模式解决的问题,就不会看错。
关于本系列文章
本来这些内容都是用来进行公司内部每周知识分享活动的,既然有一些内容了,想想不妨就整理一下贴出来吧。
也正由于这个原因,文章中的一些例子都基于团队内部成员所能理解的一些项目,可能这些项目对大家来说比较陌生,不过好处是例子相对比较贴近实际一点。
本系列一共有20篇左右,除了介绍23种GOF设计模式中常用的一部分之外(一些设计模式的思想在C#语言中有了更简单的实现,一些设计模式不是很常用)还可能会介绍一些其它有用的设计模式。
在这些文章中,我不会过多去说一些理论上的东西,也不会有结构图(这些内容网上到处都是),所有的内容都是围绕相对实际例子展开。
我想,只有这样才能更快的吸收设计模式的神而不是其形。
在看文章的时候建议你结合《设计模式》一书以及博客园的其它设计模式相关文章一起看,这样才能对设计模式理解的全面和充分一点。
每一篇文章都会有以下部分:
● 意图:
抄设计模式一书的,因为意图实在是太重要,所以不得不首先列出。
● 场景:
以一个实际的场景来说明为什么要引入设计模式。
● 示例代码:
对引入设计模式后场景的说明。
● 代码说明:
说明设计模式中的几个角色以及代码中需要注意的地方。
● 何时采用:
从代码和应用两个角度说明何时采用这个模式。
● 实现要点:
实现这种模式必要的几个地方,或者说模式主要的特点在哪里。
● 注意事项:
模式的优点缺点以及什么时候不应该使用设计模式。
无废话C#设计模式之二:
Singleton
意图
保证一个类只有一个实例,并提供访问它的全局访问点。
场景
我们现在要做一个网络游戏的服务端程序,需要考虑怎么样才能承载大量的用户。
在做WEB程序的时候有各种负载均衡的方案,不管是通过硬件实现还是软件实现,基本的思想就是有一个统一的入口,然后由它来分配用户到各个服务器上去。
需要考虑的问题是,即使在多线程的并发状态下,用户只能通过一个唯一的入口来分配,由此引入了Singleton模式来实现这个唯一的入口。
示例代码
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Threading;
namespaceSingletonExample
{
classProgram
{
staticvoidMain(string[]args)
{
ParameterizedThreadStartts=newParameterizedThreadStart(EnterPlayer);
for(inti=0;i<20;i++)
{
Threadt=newThread(ts);
t.Start("player"+i);
}
LoadBalanceServer.GetLoadBalanceServer().ShowServerInfo();
}
staticvoidEnterPlayer(objectplayerName)
{
LoadBalanceServerlbs=LoadBalanceServer.GetLoadBalanceServer();
lbs.GetLobbyServer().EnterPlayer(playerName.ToString());
}
}
classLoadBalanceServer
{
privateconstintSERVER_COUNT=3;
privateList
privatestaticvolatileLoadBalanceServerlbs;
privatestaticobjectsyncLock=newobject();
privateLoadBalanceServer()
{
for(inti=0;i { serverList.Add(newLobbyServer("LobbyServer"+i)); } } publicstaticLoadBalanceServerGetLoadBalanceServer() { if(lbs==null) { lock(syncLock) { if(lbs==null) { Thread.Sleep(100); lbs=newLoadBalanceServer(); } } } returnlbs; } publicLobbyServerGetLobbyServer() { LobbyServerls=serverList[0]; for(inti=1;i { if(serverList[i].PlayerList.Count ls=serverList[i]; } returnls; } publicvoidShowServerInfo() { foreach(LobbyServerlsinserverList) { Console.WriteLine("================="+ls.ServerName+"================="); foreach(stringplayerinls.PlayerList) { Console.WriteLine(player); } } } } classLobbyServer { privateList publicList { get{returnplayerList;} } privatestringserverName; publicstringServerName { get{returnserverName;} } publicLobbyServer(stringserverName) { this.serverName=serverName; } publicvoidEnterPlayer(stringplayerName) { playerList.Add(playerName); } } } 代码执行结果如下图: 代码说明 ● LoadBalanceServer类实现了Singleton模式,也就是说无论在什么情况下,只会有一个LoadBalanceServer类的实例出现。 ● LobbyServer类表示大厅服务,用户进入大厅后和大厅服务进行服务,在这里我们仅仅在大厅服务里面保存了用户列表。 ● Singleton模式有很多实现方式,在这里使用的是双重锁定方式。 对于C#来说,可能使用静态初始化方式是最简洁的,这里就不演示了。 ● LoadBalanceServer类的GetLobbyServer()方法负责返回一个压力最小的LobbyServer对象。 ● 实例化LoadBalanceServer的时候Sleep了线程,目的是模拟高并发的情况,在正式代码中没有必要这样做。 何时采用 ● 从代码角度来说,当你希望类只有一个实例的时候。 ● 从应用角度来说,你希望有一个总管来负责某一件事情。 并且这件事情的分配只能有一个人进行,如果有多个人进行肯定会弄乱。 比如创建处理流水号如果有两个地方在创建的话是不是就会重复了呢? 实现要点 ● 一个Singleton类,它能确保自身的实例是唯一的。 注意事项 ● 不要滥用Singleton模式,只有非一个实例不可的情况下才考虑引入Singleton。 否则,程序的可扩展性可能会受到限制。 无废话C#设计模式之三: AbstractFactory 意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 场景 还是上次说的那个网络游戏,定下来是一个休闲的FPS游戏。 和CS差不多,8到16个玩家在游戏里面分成2组对战射击。 现在要实现初始化场景的工作。 要呈现一个三维物体一般两个元素是少不了的,一是这个物体的骨架,也就是模型,二就是这个骨架上填充的纹理。 我们知道,这样的一个游戏不可能只有一张地图,而且地图的数量肯定是会一直增加的。 如果游戏在初始化场景的时候需要根据不同的地图分别加载模型和纹理对象,那么势必就会使得场景的扩充变得很不方便。 由此,我们引入AbstractFactory,抽象工厂生产的都是实际类型的接口(或者抽象类型),如果加了新的场景可以确保不需要修改加载场景的那部分代码。 示例代码 usingSystem; usingSystem.Reflection; namespaceAbstractFactoryExample { classProgram { staticvoidMain(string[]args) { Patrixpatrix=newPatrix(); patrix.LoadScene("HalfPaper"); patrix.LoadScene("Matrix"); } } classPatrix { privatePatrixSceneFactoryGetGameScene(stringgameSceneName) { return(PatrixSceneFactory)Assembly.Load("AbstractFactoryExample").CreateInstance("AbstractFactoryExample."+gameSceneName); } publicvoidLoadScene(stringgameSceneName) { PatrixSceneFactorypsf=GetGameScene(gameSceneName); Texturetexture=psf.CreateTexture(); Modelmodel=psf.CreateModel(); model.FillTexture(texture); } } abstractclassPatrixSceneFactory { publicabstractModelCreateModel(); publicabstractTextureCreateTexture(); } abstractclassModel { publicabstractvoidFillTexture(Texturetexture); } abstractclassTexture { } classHalfPaper: PatrixSceneFactory { publicoverrideModelCreateModel() { returnnewHalfPaperModel(); } publicoverrideTextureCreateTexture() { returnnewHalfPaperTexture(); } } classHalfPaperModel: Model { publicHalfPaperModel() { Console.WriteLine("HalfPaperModelCreated"); } publicoverridevoidFillTexture(Texturetexture) { Console.WriteLine("HalfPaperModelisfilledTexture"); } } classHalfPaperTexture: Texture { publicHalfPaperTexture() { Console.WriteLine("HalfPaperTextureCreated"); } } classMatrix: PatrixSceneFactory { publicoverrideModelCreateModel() { returnnewMatrixModel(); } publicoverrideTextureCreateTexture() { returnnewMatrixTexture(); } } classMatrixModel: Model { publicMatrixModel() { Console.WriteLine("MatrixModelCreated"); } publicoverridevoidFillTexture(Texturetexture) { Console.WriteLine("MatrixModelisfilledTexture"); } } classMatrixTexture: Texture { publicMatrixTexture() { Console.WriteLine("MatrixTextureCreated"); } } } 代码执行结果如下图: 代码说明 ● PatrixSceneFactory就是一个抽象工厂,它声明了创建抽象的场景以及抽象的纹理的接口。 (广告时间: Patrix是我公司的一款休闲FPS游戏,详细请见) ● Model和Texture是抽象产品。 在Model类中有一个抽象方法,用于为模型填充纹理。 ● HalfPaper和Matrix是具体工厂,它用于创建某个场景的模型和纹理。 (你可能对两个类的名字不太理解,其实HalfPaper和Matrix是两个地图的名字) ● xxxModel和xxxTexture就是具体的产品了。 它们就是针对某个场景的模型和纹理,具体工厂负责创建它们。 ● Patrix这个类负责加载场景,为了避免加载不同场景使用case语句,在这里我们使用反射来加载具体工厂类。 ● 可以看到,一旦有了新的场景(或者说地图),我们只需要设计新的xxxModel和xxxTexture以及具体工厂类就可以了,加载场景的那部分代码(也就是Patrix类)不需要做改动。 ● 我们现在这个游戏可是不支持和电脑对战的,万一以后需要支持电脑了,那么场景中的元素除了纹理和模型之外就还需要加电脑了。 也就是说抽象工厂还需要多生产一种类型的产品,这个时候抽象工厂就无能为力了。 抽象工厂只能解决系列产品扩张的变化点(在我们的例子中就是地图的新增),因此千万把抽象工厂所能生产的产品考虑周全了。 何时采用 ● 从代码角度来说,你希望在统一的地方创建一系列相互关联的对象,并且基于抽象对象的时候。 ● 从应用角度来说,如果你的产品是成组成套的,并且肯定会不断扩展新系列的,那么就适用抽象工厂。 比如说,外面买的塑料模型,里面总是有图纸、模型元件板和外壳包装三部分。 那么生产模型的厂就是抽象工厂,打印图纸、打印包装盒以及生产元件板的三个流水线就是具体工厂了。 需要生产新的模型,只需要制作新的图纸输入到三个流水线的电脑中就可以了。 实现要点 ● 抽象工厂本身不负责创建产品,产品最终还是由具体工厂来创建的。 比如,MatrixModel是Matrix创建的,而不是PatrixSceneFactory创建的。 在.NET中可以使用反射来创建具体工厂,从而使得代码变动降到最低。 ● 在抽象工厂中需要体现出生产一系列产品。 这一系列产品是相互关联,相互依赖一起使用的。 ● 抽象工厂对应抽象产品,具体工厂对应具体产品,外部依赖抽象类型,这样对于新系列产品的创建,外部唯一依赖的就是具体工厂的创建过程(可以通过反射解决)。 注意事项 ● 一般来说需要创建一系列对象的时候才考虑抽象工厂。 比如,创建一个场景,需要创建模型和纹理,并且模型和纹理之间是有一定联系的,不太可能把PatrixTexture套用在MatrixModel上。 ● 如果系统的变化点不在新系列的扩充上,那么就没有必要使用抽象工厂。 比如,如果我们不会增加新地图的话,那么也就没有必要引入抽象工厂。 .NET中的抽象工厂 ● 我们说过,抽象工厂针对系列产品的应变。 在使用ADO.NET进行数据访问的时候,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 废话 设计 模式
![提示](https://static.bdocx.com/images/bang_tan.gif)