随笔 - 34  文章 - 0 评论 - 1109 trackbacks - 0

摘要: 如果能把自我介绍做好,即便技术不行,将来也一定能胜任未来的工作;因为自我介绍也是一项工作,并且是可以看到可以评估的工作;阅读全文
posted @ 2011-11-24 22:41 倪大虾 阅读(3388) 评论(35) 编辑
摘要: 简介对于ASP.NET开发人员来说,管理项目中的JavaScript都很随意:我想这很大程度上可能是因为网上没有如何妥善处理ASP.NET中JavaScript的可靠信息。此文的目的就是提供一种最佳方案,用于管理ASP.NET中的JavaScript。该方案将能解决以下问题:内联JS:把JS直接放在页面中将导致页面臃肿不堪。 发布JS:经常忘记发布JS文件。 错误引用:在其它Web程序中引用JS时...阅读全文
posted @ 2011-06-02 09:29 倪大虾 阅读(4218) 评论(49) 编辑
摘要: 简介 自上篇翻译<如何向妻子解释OOD>后收到了很好的反应。故特继续翻译作者的<How I explained Design Patterns to my wife: Part 1>一文,以飨读者。在此文中,作者依旧通过与妻子浅显易懂的对话,向读者解释了什么是设计模式。设计模式是什么?Shubho:通过我们关于面向对象设计原则(OODP,即SOLID原则)的对话,我想你已经对面向对象设计原则(OODP)有了基本的认识。希望你不要介意我把对话分享到博客上。你可以在这找到它:<如何向妻子解释OOD>.设计模式是这些原则在某些特定公共场景下标准化的应用,接下来让我阅读全文
posted @ 2011-05-30 09:55 倪大虾 阅读(4166) 评论(24) 编辑
摘要: 前言  此文译自CodeProject上<How I explained OOD to my wife>一文,该文章在Top Articles上排名第3,读了之后觉得非常好,就翻译出来,供不想读英文的同学参考学习。  作者(Shubho)的妻子(Farhana)打算重新做一名软件工程师(她本来是,后来因为他们孩子出生放弃了),于是作者就试图根据自己在软件开发设计方面的经验帮助她学习面向对象设计(O...阅读全文
posted @ 2011-01-25 21:47 倪大虾 阅读(35721) 评论(121) 编辑
摘要: 最近有人向我询问如何学习,工作的问题,思前想后,觉得习惯最重要,于是就想到整理一下自己的学习工作习惯。本人工作比较随便,谈不上章法,就随便列举一些。1,正常的作息时间2,工作便条3,日志4,使用好办公软件5,强大小工具:计算器,画图,记事本...6,帮助别人,向他人学习7,贪多嚼不烂8,总结1,正常的作息时间  个人觉得这点最重要,所以就放在了第一项。也许是年龄增大的缘故,现在根本熬夜不得。现在每...阅读全文
posted @ 2010-11-03 08:42 倪大虾 阅读(3999) 评论(58) 编辑
摘要: 前言前段时间忙了一阵子Google Earth,这周又忙了一阵子架构师论文开题报告,现在终于有时间继续<WPF之路>了。先回忆一下上篇的内容,在《从HelloWorld到WPF World》中,我们对WPF有了个大概的了解,并了解了初学WPF时应该从哪些知识点入手。今天我们就从最基本的知识点之一布局系统来继续学习WPF,主要包括如下内容。 0,什么是布局1,基本元素—&md...阅读全文
posted @ 2010-10-31 22:04 倪大虾 阅读(4537) 评论(35) 编辑
摘要: 今天看到园子里周金根的《个人管理:程序员应不应该离职,我该何去何从呢?》一文,读完之后就想写出自己的观点——个人离职的第四个理由——挑战与经历!  周兄能在一家公司工作十年,这种经历想来不多,我自问自己做不到。而周兄给出了三个离职理由(职业方向,环境氛围,工资奖金)也很恰当,在赋以充分的说明,更引起了大家的共鸣。然而人生就是如此吗?!  我相信人与人...阅读全文
posted @ 2010-10-18 22:06 倪大虾 阅读(3472) 评论(53) 编辑
摘要: 前言  有人说到,学习任何一种编程最困难的部分是“Hello World”。这一看似乎很可笑,仔细想来却未必。平时很多我们自认为很简单的东西也许恰恰是最困难的东西,比如C#中的一些基本概念,我们天天都在用,可你真的都理解他们吗?!对很多人来说恐怕要打个问号了。  最近开始学习使用WPF,WPF是什么?网上有很多文章,在此就不赘述了。  一切还是从“Hello World”开始,然而因为有了上面的经...阅读全文
posted @ 2010-10-17 21:54 倪大虾 阅读(2551) 评论(27) 编辑
摘要: 前言  过去我的一个朋友常说,学习任何编程语言最困难的部分是运行“Hello World”,之后一切都很容易。多年以后,我才意识到他说的很对。学习设计模式的基本目标是要用它,尤其是帮助那些有扎实的OOP基础,而对设计模式很困惑的人在设计中应用它。我不会为不同设计模式写很全面的参考,但我希望这些文章能让你入门。设计模式与特定的语言无关。虽然我用C#写了很多示例,但我尽量避免一...阅读全文
posted @ 2010-10-10 22:24 倪大虾 阅读(2310) 评论(11) 编辑
摘要: 简介  在.NET中,委托,匿名方法和Lambda表达式很容易发生混淆。我想下面的代码能证实这点。下面哪一个First会被编译?哪一个会返回我们需要的结果?即Customer.ID=5.答案是6个First不仅被编译,并都获得正确答案,且他们的结果一样。如果你对此感到困惑,那么请继续看这篇文章。什么是委托?  现在你定义一个处理用户订单的购物车ShoppingCart类。管理层决定根据数量,价格等...阅读全文
posted @ 2010-10-07 22:06 倪大虾 阅读(5664) 评论(36) 编辑
摘要: 今天重新看C#中委托,匿名方法等概念,脑子里突然冒出这么一个想法:未来高级语言编程会是什么样子,有哪些东西我们不用关心,现在拿出来给大家讨论一下。  我这里所说的高级语言是指最早的面向对象语言C++,Pascal等,后来的Smalltalk等,以及现代语言C#和Java,直到今天最新C# 4.0。注意:这里有2个C#,我没有写错,理由稍后再说。  大家知道,C++是从C扩展而来,所以它既支持面向过...阅读全文
posted @ 2010-09-25 21:21 倪大虾 阅读(3825) 评论(73) 编辑
摘要: 引言  本篇文章主要介绍.NET中6个重要的概念:栈,堆,值类型,引用类型,装箱,拆箱。文章开始介绍当你声明一个变量时,编译器内部发生了什么,然后介绍两个重要的概念:栈和堆;最后介绍值类型和引用类型,并说明一些有关它们的重要原理。  最后通过一个简单的示例代码说明装箱拆箱带来的性能损耗。声明变量的内部机制  在.NET程序中,当你声明一个变量,将在内存中分配一块内存。这块内存分为三部分:1,变量名...阅读全文
posted @ 2010-09-20 21:36 倪大虾 阅读(8287) 评论(113) 编辑
摘要: 题记:    《.NET中的设计模式》系列随笔停下有一段时间了,一则总结个东西不容易,另一则,不想写相同的内容(如果朋友们没有在我的随笔中看到新东西,我认为是浪费大家的时间,也是一种失败)。  今天开题之前先让大家见一个老朋友,相信没有一个人会不认识它:-)大家是不是觉得很眼熟啊。程序中产生一个错误的原因很简单,解决方法也很简单,我也相信写过两年代码的人只要稍微细心一点就很少遇到这个问题。抛去原因...阅读全文
posted @ 2010-09-04 16:24 倪大虾 阅读(1583) 评论(20) 编辑
摘要: 你是否正在被不断变化的需求折磨得焦头烂额?!  你是否在为繁冗复杂项目抓耳挠腮?!  相信这是很多人现在正面临的问题。我们在学习软件架构时经常能看到拥抱变化的字眼,我们也知道什么是拥抱变化,也知道拥抱变化是解决上述问题的最优途径。然而,如何拥抱变化才是解决问题的关键所在。每每此时,各种书本都会把路标指向设计模式,各种架构模式等,大家每个人看了以后大都恍然大悟,而付诸于实践时则仍旧一脸茫然。那么如何...阅读全文
posted @ 2010-08-29 23:27 倪大虾 阅读(1762) 评论(9) 编辑
摘要: 我们知道,软件架构的过程是一个抽象的过程。通常的开发人员只是从开发的角度对业务需求进行抽象建模,力求对每一个细节进行把握。由于大多数架构师来自于当初的程序员,因此经常出现对某些细节过分关注而忽视建立整体概念架构。大多数情况下出现这种情况是因为架构师没有从开发视角转换到架构视角。  在软件开发过程中,软件架构师处于非常特殊的地位。一方面,软件架构师需要与用户沟通,收集整理用户的需求;另一方面需要从整...阅读全文
posted @ 2010-08-28 23:53 倪大虾 阅读(1481) 评论(2) 编辑
摘要: 经常做WinForm开发的人可能会遇到这样一种情况,WinForm程序后台有许多线程在执行任务,前台界面需要适时或定时显示后台任务执行的情况。此类任务界面通常如下:  这里存在一个问题是如何在界面上显示后台线程上的状态数据,也就是多线程如何访问控件。  .NET中的控件并不是线程安全的,因此我们通常是用如下方法在界面上显示后台线程的数据:此类方法存在一些问题:  1,更新代码比较多,且比较晦涩难懂...阅读全文
posted @ 2010-08-21 17:51 倪大虾 阅读(1478) 评论(28) 编辑
摘要: 如果要做为一名合格的软件架构师,AOP是必须知道的一门技术。那么AOP是什么呢,这就是今天所讨论的内容(也是本人最近一阵子的学习总结,希望大家多多指点)。  AOP,全称Aspect Oriented Programming,中文名称叫面向方面编程,也叫面向切面编程。  在实际项目开发过程中,我们往往会注意到有一些模块/功能,如权限,缓存等,需要存在于软件的各个业务模块中,而这些模块/功能又与业务...阅读全文
posted @ 2010-08-21 16:02 倪大虾 阅读(1901) 评论(3) 编辑
摘要: 本文演示了如何使用.NET Framework提供的代理模式框架实现GOF23种设计模式中的代理模式。阅读全文
posted @ 2010-08-16 20:56 倪大虾 阅读(1558) 评论(17) 编辑
摘要: 在上一篇随笔<软件架构师之职责范围>中评论,yongfa365希望能看到.NET高级软件工程师的职责范围。我思前想后,还是决定说一下自己在这方面的愚见,希望大家不吝赐教。  什么是“高级软件工程师“,这个职位到底该做些什么,相信大家都有答案。在目前很多国内软件企业中,如果你是”高级软件工程师“,那么从需求分析,设计,开发,测试,甚至到客户...阅读全文
posted @ 2010-08-10 22:26 倪大虾 阅读(5772) 评论(39) 编辑
摘要: 上一篇<软件架构师之基本素质>讲述了做为一名合格的架构师应该具备哪些基本条件。当我们具备了这些条件的时候就可以选择成为架构师了。这时候我们就应该知道软件架构师应该做些什么,不应该做些什么,也就是软件架构师的职责范围。  由于国内外软件土壤差别巨大,适合国外的一些理论在国内不一定行的通,而国内的一些资料往往都是根据国外的资料直接搬过来用的,这也直接导致国外的软件架构师在国内变得水土不服。...阅读全文
posted @ 2010-08-04 21:36 倪大虾 阅读(3844) 评论(26) 编辑
摘要: 如果能把自我介绍做好,即便技术不行,将来也一定能胜任未来的工作;因为自我介绍也是一项工作,并且是可以看到可以评估的工作;阅读全文
posted @ 2011-11-24 22:41 倪大虾 阅读(3388) 评论(35) 编辑
摘要: 简介对于ASP.NET开发人员来说,管理项目中的JavaScript都很随意:我想这很大程度上可能是因为网上没有如何妥善处理ASP.NET中JavaScript的可靠信息。此文的目的就是提供一种最佳方案,用于管理ASP.NET中的JavaScript。该方案将能解决以下问题:内联JS:把JS直接放在页面中将导致页面臃肿不堪。 发布JS:经常忘记发布JS文件。 错误引用:在其它Web程序中引用JS时...阅读全文
posted @ 2011-06-02 09:29 倪大虾 阅读(4218) 评论(49) 编辑

简介

  自上篇翻译<如何向妻子解释OOD>后收到了很好的反应。故特继续翻译作者的<How I explained Design Patterns to my wife: Part 1>一文,以飨读者。在此文中,作者依旧通过与妻子浅显易懂的对话,向读者解释了什么是设计模式。

设计模式是什么?

Shubho:通过我们关于面向对象设计原则(OODP,即SOLID原则)的对话,我想你已经对面向对象设计原则(OODP)有了基本的认识。希望你不要介意我把对话分享到博客上。你可以在这找到它:<如何向妻子解释OOD>.

设计模式是这些原则在某些特定公共场景下标准化的应用,接下来让我们通过一些例子学习什么是设计模式。

Farhana: 当然,我喜欢例子。

Shubho: 让我们以汽车为例讨论一下。汽车是一个很复杂的对象,由成千上万的其它对象组成,如发动机,车轮,方向盘,车座,车体等等其他不同的部分或部件。

汽车部件

当装配汽车时,制造商需要集中并装配这些更小的自成汽车子系统的不同部件。而这些不同的小部件同样也是复杂的对象,其它制造商同样要生产并组装它们。在生产汽车时,汽车公司并不会为怎么生产组装这些部件操心(前提是他们要确保这些对象/设备的质量)。当然,汽车制造商更加关心怎么装配这些不同部件以便能生产不同型号的汽车。

通过遵循不同的设计,组装不同的部件,生产不同型号的汽车

Farhana: 汽车制造公司必须有如何生产不同型号汽车的设计图或蓝图,对吗?

Shubho: 当然,并且这些设计都是良好的,他们花费大量的时间和精力来做这些设计。一旦设计完成,生产汽车就仅仅是照葫芦画瓢了。

Farhana: 嗯。如果事先有一些好的设计,就能在短时间内遵照这些设计生产不同产品,并且制造商在每次生产某一个型号产品时就不需要重新设计或重新发明车轮,他们只需要按照已有的设计办事就行了。

生产不同型号产品(汽车)的不同设计图

Shubho: 你抓到重点了。现在假设我们是软件生产商,我们使用基于需求而来的不同组件或功能构建各种不同的软件程序。当生产这些不同软件系统时,我们常常需要为一些不同软件系统中存在的相同情况开发代码,对吗?

Farhana: 是的,在开发不同软件程序时经常遇到相同的设计问题。

Shubho: 我们尝试使用面向对象的方式开发软件,并尝试应用OOPD来让代码能易于维护,可复用,可扩展。无论什么时候,当我们遇到这些设计问题时,如果我们有一组经过谨慎开发,良好测试的对象以供使用会不会更好呢?

Farhana: 是的,这样能够节省时间,生产出更好的软件,且利于以后维护。

Shubho: 很好!从设计上来说,它的好处是你不需要开发那些对象。经过多年发展,人们已经遇到过一些类似的设计问题,并已经形成有一些公认的,良好的已标准化的设计方案。我们称之为设计模式。

我们一定好感谢四人组,他们在《设计模式:可复用面向对象软件设计》中总结出了23种基本的设计模式。四人组由Erich Gamma, Richard Helm, Ralph Johnson, 和John Vlissides组成。实际中有很多面向对象设计模式,但这23种模式被公认为是所有其他设计模式的基础。

Farhana: 我能发明一个新的模式吗?这可能吗?

Shubho: 当然,亲爱的,为什么不能呢?!设计模式不是由科学家发明创造的。它们是被发现找到的。这意味着任何通用问题场景中都有一些好的设计方案在那。如果我们能够指出一个能够解决一个新的设计相关问题的面向对象设计,那么这将会是一个由我们定义的新的设计模式。谁知道呢?!如果我们发现找到一些设计模式,或许将来有一天人们会称我们为二人组,哈哈。

Fahana: :)

我们将如何学习设计模式?

Shubho: 我一直认为例子是学习的最好途径。在我们的学习方法中,我们不会先讨论理论后讨论实现。我认为这是很糟糕的方式。设计模式不是基于理论的发明。事实上,问题场景首先出现,其次是基于这些问题的来龙去脉和需求,然后是一些设计方案的演化,最后其中的一些被标准化为模式。所以对每一个我们讨论的设计模式,我们将尝试理解并分析一些现实生活中的例子,然后一步步尝试归纳一个设计,并最后总结一些与某些模式匹配设计。设计模式就是在这些相似过程中发现的。你认为呢?

Farhana:我想这种方式对我更有用。如果我能通过分析问题和归纳方案得出设计模式,我就不用死记那些设计模式和定义了。请按照你的方式继续。

一个常见的设计问题和它的解决方案

Shubho: 让我们考虑下面的场景:

我们房间里有些电器(电灯,风扇等)。这些设备按照某些方式布局,并由开关控制。任何时候你都能替换或排查一个电器而不用碰到其他东西。例如,你可以换一个电灯而不需要换开关。同样,你可以换一个开关或排查它而不需要碰到或替换相应的电灯或风扇;甚至你可以用把电灯连接到风扇的开关上,把风扇连到电灯的开关上,而不需要碰到开关。

电器:风扇和电灯

风扇和电灯的两种不同开关,一个普通点,另一个别致点

Farhana: 是的,但就是这样子,对吗?

Shubho: 是的,确实如此,就该如此布局。当不同东西联系在一起时,它们应该按照一定方式联系:修改或替换一个系统时不会影响到另一个,或者说即便有,也应该最小化。这能够让你的系统易于管理,且成本低。想想一下,如果改一下房间里的灯同时需要改开关,你会乐意在你房子上花钱并安装这个系统吗?

Farhana: 当然不会。

Shubho: 现在,让我们思考一下电灯或风扇如何连接到开关上才能达到改变一个不会影响到另一个。你认为该如何?

Farhana: 用电线!

Shubho: 很好。把电灯/风扇和开关联系到一起的是电线和电器布局。我们可以它们看做不同系统间相互联系的桥梁。其基本的思想是,一个事物不能和另一外一个事物直接联系。当然啦,它们应当通过某些桥梁或接口联系在一起。用软件术语来说,这叫“松耦合”。

Farhana: 我知道了。

Shubho: 现在,让我们尝试推断在电灯/风扇和开关例子中的几个关键问题,并尝试推断它们是如何设计并联系起来的。

Farhana: 好,我们试一下。

例子中我们有开关,可能有几种开关,如普通的开关,漂亮的开关,但通常来说它们还是开关,并且每种开关都能够打开和关闭。

所以下面我们会有一个开关基类Switch

public class Switch {
public void On() {
//打开开关
}
public void Off() {
//关闭开关
}
}

接下来我们可以有一些具体的开关,例如一个漂亮开关,一个普通开关等等,当然,我们会让类FancySwitchNormalSwitchnd继承类Switch

public class NormalSwitch : Switch {
}
public class FancySwitch : Switch {
}
这里的两个具体类有自己的特征和行为,只是此时此刻,我们简单化以下。

Shubho: 非常棒,接下来电灯和风扇怎么办?

Farhana: 我试试. 根据OODP的开放闭合原则,我们知道只要可能,就应该尝试抽象,对吗?

Shubho: 对

Farhana: 跟开关不一样,风扇和电灯等是两种不同的事物。对于开关,我们能够使用一个开关基类Switch,但风扇和电灯是两个不同的事物,相比定义一个基类,接口可能更合适。一般来说,他们都是电器。所以我们可以定义一个接口,如IElectricalEquipment,作为对电灯和风扇的抽象,可以吗?

Shubho: 可以

Farhana: 好,每种电器都有些相同的功能。他们能够打开和关闭。所以接口可能如下:

public interface IElectricalEquipment {
void PowerOn(); //每种电器都能打开
void PowerOff(); //每种电器都能关闭
}
Shubho: 太好了,你很善于抽象东西。现在我们需要一座桥梁。在现实中,电线是桥梁。在我们对象设计中,开关知道如何打开和关闭电器,电器以某种方式联系到开关。这里我们没有电线,让电器连接到开关的唯一方式是封装。

Farhana: 是的,但开关不能直接知道风扇或电灯。开关应当知道一个电器IElectricalEquipment能够打开或关闭。这意味着,ISwitch应该有一个IElectricalEquipment实例,对吗?

Shubho: 对,对风扇或电灯的封装的实例是一个桥梁。所以让我们修改Switch类以便封装一个电器:

public class Switch {
public IElectricalEquipment equipment {
get;
set;
}
public void On() {
//开关打开
}
public void Off() {
//开关关闭
}
}
Farhana: 明白。让我们定义真实的电器:风扇和电灯。如我所见,一般来说它们都是电器,所以它们都简单实现了IElectricalEquipment接口。

下面是风扇类:

public class Fan : IElectricalEquipment {
public void PowerOn() {
Console.WriteLine(
"风扇打开");
}
public void PowerOff() {
Console.WriteLine(
"风扇关闭");
}
}

下面是电灯类:

public class Light : IElectricalEquipment {
public void PowerOn() {
Console.WriteLine(
"电灯打开");
}
public void PowerOff() {
Console.WriteLine(
"电灯关闭");
}
}

Shubho:太好了。现在让开关工作。当开关打开关闭的时候它应当能够打开关闭电器(它连接到的) 。

这里的关键点是:

大致的代码如下:

static void Main(string[] args) {
//构造电器设备:风扇,开关
IElectricalEquipment fan = new Fan();
IElectricalEquipment light
= new Light();

//构造开关
Switch fancySwitch = new FancySwitch();
Switch normalSwitch
= new NormalSwitch();

//把风扇连接到开关
fancySwitch.equipment = fan;

//开关连接到电器,那么当开关打开或关闭时电器应该打开/关闭
fancySwitch.On();
fancySwitch.Off();

//把电灯连接到开关
fancySwitch.equipment = light;
fancySwitch.On();
//打开电灯
fancySwitch.Off(); //关闭电灯
}

Farhana: 明白。开关的On()方法应当内部调用电器的TurnOn()方法,Off()方法应当内部调用TurnOff()方法,所以开关类Switch应如下:

public class Switch {
public IElectricalEquipment equipment {
get;
set;
}
public void On() {
Console.WriteLine(
"开关打开");
equipment.PowerOn();
}
public void Off() {
Console.WriteLine(
"开关关闭");
equipment.PowerOff();
}
}

Shubho: 很好。这自然允许你把风扇从一个开关接到另一个上。不过你看,反过来也可以。这意味着你可以改变风扇或电灯的开关而不需要碰到风扇或电灯。例如,你可以很轻松的把点灯的开关从FancySwitch换到NormalSwitch上,如下:

normalSwitch.equipment = light;
normalSwitch.On();
//打开电灯
normalSwitch.Off(); //关闭电灯
你看,连接一个抽象电器到一个开关(通过封装)能够让你改变开关和电器而不会对对方产生影响。这个设计是优雅的,良好的。四人组为该模式取名为:桥接模式。

Farhana: 太棒了。我想我明白这个了。从根本上说,两个系统不应当直接联系或依赖与对方。 当然,他们应该联系或依赖于抽象(如依赖倒置原则和开放闭合原则所讲),所以他们是松耦合的,因此我们可以在需要时改变我们的实现而不会对系统其他部分产生过多影响。

Shubho: 你理解了,亲爱的.我们看下桥接模式的定义:

"将抽象部分与实现部分分离,使它们都可以独立的变化"

你看我们的实现完美遵循该定义。如果你有一个类设计器(如Visual Studio或其他支持该功能的IDE环境),你会看到类似的如下类图:

桥接模式类图

在这里, Abstraction开关基类Switch RefinedAbstraction 是具体开关类 (FancySwitch, NormalSwitch 等等。)。 Implementor 是电器接口IElectricalEquipmentConcreteImplementorA 和ConcreteImplementorB 是电灯类Light和风扇类Fan

Farhana: 问你个问题,只是好奇啊。如你所说有很多其他的设计模式,为什么你以桥接模式开始呢?有重要原因吗?

Shubho: 这个问题很好。是的,我以桥接模式而不以其他开始是因为一个理由。我认为桥接模式是所有面向对象模式的基础。理由如下:

Farhana: 你认为我理解的对吗?

Shubho: 我认为你理解的非常正确。

Farhana: 那么接下来是什么?

Shubho: 通过理解桥接模式,我们仅仅是开始理解设计模式的思想。在我们接下的对话中,我们将会学习其他的设计模式,我希望你不会觉得它们无聊。

Farhana:不会的,相信我。

posted @ 2011-05-30 09:55 倪大虾 阅读(4166) 评论(24) 编辑

前言

  此文译自CodeProject上<How I explained OOD to my wife>一文,该文章在Top Articles上排名第3,读了之后觉得非常好,就翻译出来,供不想读英文的同学参考学习。

  作者(Shubho)的妻子(Farhana)打算重新做一名软件工程师(她本来是,后来因为他们孩子出生放弃了),于是作者就试图根据自己在软件开发设计方面的经验帮助她学习面向对象设计(OOD)。

  自作者从事软件开发开始,作者常常注意到不管技术问题看起来多复杂,如果从现实生活的角度解释并以对答的方式讨论,那么它将变得更简单。现在他们把在OOD方面有些富有成效的对话分享出来,你可能会发现那是一种学习OOD很有意思的方式。

  下面就是他们的对话:

OOD简介

Shubho:亲爱的,让我们开始学习OOD吧。你了解面向对象原则吗?

Farhana:你是说封装,继承,多态对吗?我知道的。

Shubho:好,我希望你已了解如何使用类和对象。今天我们学习OOD。

Farhana:等一下。面向对象原则对面向对象编程(OOP)来说不够吗?我的意思是我会定义类,并封装属性和方法。我也能根据类的关系定义它们之间的层次。如果是,那么还有什么?

Shubho:问得好。面向对象原则和OOD实际上是两个不同的方面。让我给你举个实际生活中的例子帮你弄明白。

     再你小时候你首先学会字母表,对吗?

Farhana:嗯

Shubho:好。你也学了单词,并学会如何根据字母表造词。后来你学会了一些造句的语法。例如时态,介词,连词和其他一些让你能造出语法正确的句子。例如:

  "I" (代词) "want" (动词) "to" (介词) "learn" (动词) "OOD"(名词)。

看,你按照某些规则组合了单词,并且你选择了有某些意义的正确的单词结束了句子。

Farhana:OK,这意味着什么呢?

Shubho:面向对象原则与这类似。OOP指的是面向对象编程的基本原则和核心思路。在这里,OOP可以比作英语基础语法,这些语法教你如何用单词构造有意义且正确的句子,OOP教你在代 码中构造类,并在类里封装属性和方法,同时构造他们之间的层次关系。

Farhana:嗯..我有点感觉了,这里有OOD吗?

Shubho:马上就有答案。现在假定你需要就某些主题写几篇文章或随笔。你也希望就几个你擅长主体写几本书。对写好文章/随笔或书来说,知道如何造句是不够的,对吗?为了使读者能更轻   松的明白你讲的内容,你需要写更多的内容,学习以更好的方式解释它。

Farhana:看起来有点意思...继续。

Shubho:现在,如果你想就某个主题写一本书,如学习OOD,你知道如何把一个主题分为几个子主题。你需要为这些题目写几章内容,也需要在这些章节中写前言,简介,例子和其他段落。   你需要为写个整体框架,并学习一些很好的写作技巧以便读者能更容易明白你要说的内容。这就是整体规划。

  在软件开发中,OOD是整体思路。在某种程度上,设计软件时,你的类和代码需能达到模块化,可复用,且灵活,这些很不错的指导原则不用你重新发明创造。确实有些原则你已经在你的类和对象中已经用到了,对吗?

Farhana:嗯...有个大概的印象了,但需要继续深入。

Shubho:别担心,你马上就会学到。我们继续讨论下去。

为什么要OOD?

Shubho:这是一个非常重要的问题。当我们能很快地设计一些类,完成开发并发布时,为什么我们需要关心OOD?那样子还不够吗?

Farhana:嗯,我早先并不知道OOD,我一直就是开发并发布项目。那么关键是什么?

Shubho:好的,我先给你一句名言:

  走在结冰的河边不会湿鞋,开发需求不变的项目畅通无阻(Walking on water and developing software from a specification are easy if both are frozen)

  -Edward V. Berard

Farhana:你的意思是软件开发说明书会不断变化?

Shubho:非常正确!软件开发唯一的真理是“软件一定会变化”。为什么?

  因为你的软件解决的是现实生活中的业务问题,而现实生活中得业务流程总是在不停的变化。

  假设你的软件在今天工作的很好。但它能灵活的支持“变化”吗?如果不能,那么你就没有一个设计敏捷的软件。

Farhana:好,那么请解释一下“设计敏捷的软件”。

Shubho:"一个设计敏捷的软件能轻松应对变化,能被扩展,并且能被复用。"

并且应用好"面向对象设计"是做到敏捷设计的关键。那么,你什么时候能说你在代码中很好的应用了OOD?

Farhana:这正是我的问题。

Shubho:如果你代码能做到以下几点,那么你就正在OOD:

Farhana:还有?

Shubho:我们并不是孤立的。很多人在这个问题上思考了很多,也花费了很大努力,他们试图做好OOD,并为OOD指出几条基本的原则(那些灵感你能用之于你的OOD)。他们最终也确实总结出了一些通用的设计模式(基于基本的原则)。

Farhana:你能说几个吗?

Shubho:当然。这里有很多涉及原则,但最基本的是叫做SOLID的5原则(感谢Uncle Bob,伟大OOD导师)。

 

S = 单一职责原则 Single Responsibility Principle
O = 开放闭合原则 Opened Closed Principle 
L = Liscov替换原则 Liscov Substitution Principle
I = 接口隔离原则 Interface Segregation Principle
D = 依赖倒置原则 Dependency Inversion Principle

 

接下去,我们会仔细探讨每一个原则。

单一职责原则

Shubho:我先给你展示一张海报。我们应当谢谢做这张海报的人,它非常有意思。

单一职责原则海报

它说:"并不是因为你能,你就应该做"。为什么?因为长远来看它会带来很多管理问题。

从面向对象角度解释为:"引起类变化的因素永远不要多于一个。"

或者说"一个类有且只有一个职责"。

Farhana:能解释一下吗?

Shubho:当然,这个原则是说,如果你的类有多于一个原因会导致它变化(或者多于一个职责),你需要一句它们的职责把这个类拆分为多个类。

Farhana:嗯...这是不是意味着在一个类里不能有多个方法?

Shubho:不。你当然可以在一个类中包含多个方法。问题是,他们都是为了一个目的。如今为什么拆分是重要的?

那是因为:

Farhana:能给我一个例子吗?

Shubho:当然,看一下下面的类层次。当然这个例子是从Uncle Bob那里得来,再谢谢他。

违反单一职责原则的类结构图

这里,Rectangle类做了下面两件事:

并且,有两个应用使用了Rectangle类:

这违反了SRP(单一职责原则);

Farhana:如何违反的?

Shubho:你看,Rectangle类做了两件事。在一个方法里它计算了面积,在另外一个方法了它返回一个表示矩形的GUI。这会带来一些有趣的问题:

在计算几何应用程序中我们必须包含GUI。也就是在开发几何应用时,我们必须引用GUI库;

图形应用中Rectangle类的变化可能导致计算几何应用变化,编译和测试,反之亦然;

Farhana:有点意思。那么我猜我们应该依据职责拆分这个类,对吗?

Shubho:非常对,你猜我们应该做些什么?

Farhana:当然,我试试。下面是我们可能要做的:

拆分职责到两个不同的类中,如:

Shubho:非常好。在这里,Rectangle类被计算几何应用使用,而RectangleUI被图形应用使用。我们甚至可以分离这些类到两个独立的DLL中,那会允许我们在变化时不需要关心另一个就可以实现它。

Farhana:谢谢,我想我明白SRP了。SRP看起来是把事物分离成分子部分,以便于能被复用和集中管理。我们也不能把SRP用到方法级别吗?我的意思是,我们可以写一些方法,它们包含做很多事的代码。这些方法可能违反SRP,对吗?

Shubho:你理解了。你应当分解你的方法,让每个方法只做某一项工作。那样允许你复用方法,并且一旦出现变化,你能购以修改最少的代码满足变化。

开放闭合原则

Shubho:这里是开放闭合原则的海报

开放闭合原则海报

从面向对象设计角度看,它可以这么说:"软件实体(类,模块,函数等等)应当对扩展开放,对修改闭合。"

通俗来讲,它意味着你应当能在不修改类的前提下扩展一个类的行为。就好像我不需要改变我的身体而可以穿上衣服。

Farhana:有趣。你能够按照你意愿穿上不同的衣服来改变面貌,而从不用改造身体。你对扩展开放了,对不?

Shubho:是的。在OOD里,对扩展开发意味着类或模块的行为能够改变,在需求变化时我们能以新的,不同的方式让模块改变,或者在新的应用中满足需求。

Farhana:并且你的身体对修改是闭合的。我喜欢这个例子。当需要变化时,核心类或模块的源代码不应当改动。你能用些例子解释一下吗?

Shubho:当然,看下面这个例子。它不支持"开放闭合"原则。

违反开发闭合原则的类结构

你看,客户端和服务段都耦合在一起。那么,只要出现任何变化,服务端变化了,客户端一样需要改变。

Farhana:理解。如果一个浏览器以紧耦合的方式按照指定的服务器(比如IIS)实现,那么如果服务器因为某些原因被其他服务器(如Apache)替换了,那么浏览器也需要修改或替换。这确实很可怕!

Shubho:对的。下面是正确的设计。

遵循开放闭合原则的类结构

在这个例子中,添加了一个抽象的服务器类,客户端包含一个抽象类的引用,具体的服务类实现了抽象服务类。那么,因任何原因引起服务实现发生变化时,客户端都不需要任何改变。

这里抽象服务类对修改是闭合的,实体类的实现对扩展是开放的。

Farhana:我明白了,抽象是关键,对吗?

Shubho:是的,基本上,你抽象的东西是你系统的核心内容,如果你抽象的好,很可能在扩展功能时它不需要任何修改(就像服务是一个抽象概念)。如果在实现里定义了抽象的东西(比如IIS服务器实现的服务),代码要尽可能以抽象(服务)为依据。这会允许你扩展抽象事物,定义一个新的实现(如Apache服务器)而不需要修改任何客户端代码。

Liskov's 替换原则

Shubho:"Liskov's替换原则(LSP)"听起来很难,却是很有用的基本概念。看下这幅有趣的海报:

Liskov替换原则海报

这个原则意思是:"子类型必须能够替换它们基类型。"

或者换个说法:"使用基类引用的函数必须能使用继承类的对象而不必知道它。"

Farhana:不好意思,听起来有点困惑。我认为这个OOP的基本原则之一。也就是多态,对吗?为什么一个面向对象原则需要这么说呢?

Shubho:问的好。这就是你的答案:

在基本的面向对象原则里,"继承"通常是"is a"的关系。如果"Developer" 是一个"SoftwareProfessional",那么"Developer"类应当继承"SoftwareProfessional"类。在类设计中"Is a"关系非常重要,但它容易冲昏头脑,结果使用错误的继承造成错误设计。

"Liskov替换原则"正是保证继承能够被正确使用的方法。

Farhana:我明白了。有意思。

Shubho:是的,亲爱的,确实。我们看个例子:

Liskov替换原则类结构图

这里,KingFisher类扩展了Bird基类,并继承了Fly()方法,这看起来没问题。

现在看下面的例子:

违反Liskov替换原则类结构图

Ostrich(鸵鸟)是一种鸟(显然是),并从Bird类继承。它能飞吗?不能,这个设计就违反了LSP。

所以,即使在现实中看起来没问题,在类设计中,Ostrich不应该从Bird类继承,这里应该从Bird中分离一个不会飞的类,Ostrich应该继承与它。

Farhana:好,明白了。那么让我来试着指出为什么LSP这么重要:

对吗?

Shubho:非常正确。你能设计对象,使用LSP做为一个检查工作来测试继承是否正确。

接口分离原则

Shubho:今天我们学习"接口分离原则",这是海报:

接口分离原则海报

Farhana:这是什么意思?

Shubho:它的意思是:"客户端不应该被迫依赖于它们不用的接口。"

Farhana:请解释一下。

Shubho:当然,这是解释:

假设你想买个电视机,你有两个选择。一个有很多开关和按钮,它们看起来很混乱,且好像对你来说没必要。另一个只有几个开关和按钮,它们很友好,且适合你使用。假定两个电视机提供同样的功能,你会选哪一个?

Farhana:当然是只有几个开关和按钮的第二个。

Shubho:对,但为什么?

Farhana:因为我不需要那些看起来混乱又对我没用的开关和按钮。

 

Shubho:以便外部能够知道这些类有哪些可用的功能,客户端代码也能根据接口来设计.现在,如果接口太大,包含很多暴露的方法,在外界看来会很混乱.接口包含太多的方法也使其可用性降低,像这种包含了无用方法的"胖接口"会增加类之间的耦合.你通过接口暴露类的功能,对.同样地,假设你有一些类,

这也引起了其他问题.如果一个类想实现该接口,那么它需要实现所有的方法,尽管有些对它来说可能完全没用.所以说这么做会在系统中引入不必要的复杂度,降低可维护性或鲁棒性.

接口隔离原则确保实现的接口有他们共同的职责,它们是明确的,易理解的,可复用的.

Farhana:你的意思是接口应该仅包含必要的方法,而不该包含其它的.我明白了.

Shubho:非常正确.一起看个例子.

下面是违反接口隔离原则的一个胖接口
 

 

注意到IBird接口包含很多鸟类的行为,包括Fly()行为.现在如果一个Bird类(如Ostrich)实现了这个接口,那么它需要实现不必要的Fly()行为(Ostrich不会飞).

Farhana:确实如此。那么这个接口必须拆分了?

Shubho:是的。这个"胖接口"应该拆分未两个不同的接口,IBirdIFlyingBird,IFlyingBird继承自IBird.

 

 

这里如果一种鸟不会飞(如Ostrich),那它实现IBird接口。如果一种鸟会飞(如KingFisher),那么它实现IFlyingBird.

Farhana:所以回头看包含了很多开关和按钮的电视机的例子,电视机制造商应该有一个电视机的图纸,开关和按钮都在这个方案里。不论任何时候,当他们向制造一种新款电视机时,如果他们想复用这个图纸,他们将需要在这个方案里添加更多的开关和按钮。那么他们将没法复用这个方案,对吗?

Shubho:对的。

Farhana:如果他们确实需要复用方案,它们应当把电视机的图纸份为更小部分,以便在任何需要造新款电视机的时候复用这点小部分。

Shubho:你理解了。

依赖倒置原则

Shubho:这是SOLID原则里最后一个原则。这是海报

 
 

它的意思是:高层模块不应该依赖底层模块,两者都应该依赖其抽象

Shubho:考虑一个现实中的例子。你的汽车是由很多如引擎,车轮,空调和其它等部件组成,对吗?

Farhana:是的

Shubho:好,它们没有一个是严格的构建在一个单一单元里;换句话说,它们都是可插拔的,因此当引擎或车轮出问题时,你可以修理它(而不需要修理其它部件),甚至可以换一个。

在替换时,你仅需要确保引擎或车轮符合汽车的设计(如汽车能使用任何1500CC的引擎或任何18寸的车轮)。

当然,汽车也可能允许你在1500CC引擎的地方安装一个2000CC的引擎,事实上对某些制造商(如丰田汽车)是一样的。

现在,如果你的汽车的零部件不具备可插拔性会有什么不同?

Farhana:那会很可怕!因为如果汽车的引擎出故障了,你可能修理整部车或者需要买一个新的。

Shubho:是的,那么该如何做到"可插拔性"呢?

Farhana:这里抽象是关键,对吗?

Shubho:是的,在现实中,汽车是高级模块或实体,它依赖于低级模块或实体,如引擎或车轮。

相比直接依赖于引擎或车轮,汽车应依赖于某些抽象的有规格的引擎或车轮,以便于如果任何引擎或车轮符合抽象,那么它们都能组合到汽车中,汽车也能跑动。

一起看下面的类图

 
 

Shubho:注意到上面Car类有两个属性,它们都是抽象类型(接口)。引擎和车轮是可插拔的,因为汽车能接受任何实现了声明接口的对象,并且Car类不需要做任何改动。

Farhana:所以,如果代码中不用依赖倒置,我们将面临如下风险:

  • 使用低级类会破环高级代码;

  • 当低级类变化时需要很多时间和代价来修改高级代码;

  • 产生低复用的代码;

Shubho:你完全掌握了,亲爱的!

 总结

Shubho:除SOLID原则外还有很多其它的面向对象原则。如:

"组合替代继承":这是说相对于继承,要更倾向于使用组合;

"笛米特法则":这是说"你的类对其它类知道的越少越好";

"共同封闭原则":这是说"相关类应该打包在一起";

"稳定抽象原则":这是说"类越稳定,越应该由抽象类组成";

Farhana:我应该学习那些原则吗?

Shubho:当然可以。你可以从整个网上学习。仅仅需要Google一下那些原则,然后尝试理解它。当然如果有需要,尽管问我。

Farhana:在那些设计原则之上我听说过很多设计模式。

Shubho:对的。设计模式只是对一些经常出现的场景的一些通用设计建议。这些灵感主要来自于面向对象原则。你可以把设计模式看作"框架",把OOD原则看作"规范".

Farhana:那么接下去我将学习设计模式吗?

Shubho:是的,亲爱的。

Farhana:那会很有意思,对吗?

Shubho:是,那确实令人兴奋。

-------------------------------------------------------------------------------------------------------------------

声明:

  本文版权归作者共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文出处,连接,作者,否则保留追究法律责任的权利。

 

posted @ 2011-01-25 21:47 倪大虾 阅读(35721) 评论(121) 编辑

  最近有人向我询问如何学习,工作的问题,思前想后,觉得习惯最重要,于是就想到整理一下自己的学习工作习惯。本人工作比较随便,谈不上章法,就随便列举一些。

  • 1,正常的作息时间

  • 2,工作便条

  • 3,日志

  • 4,使用好办公软件

  • 5,强大小工具:计算器,画图,记事本...

  • 6,帮助别人,向他人学习
  • 7,贪多嚼不烂
  • 8,总结

  • 1,正常的作息时间

      个人觉得这点最重要,所以就放在了第一项。也许是年龄增大的缘故,现在根本熬夜不得。现在每天光顾博客园,发现有些人很晚的时候还在发贴,回帖,仿佛不知疲倦。在此衷心劝告一句:莫要透支身体!养成良好的作息规律是人生一大事,毕竟身体健康最重要,其他诸如事业,名利都是浮云!不是说人生最大的悲剧不是没钱花,而是有钱没命花么?!

      本人现在每天晚上10:00(以往12:00)左右休息,早上7:30(以往8:30)起床,加班之事少有。


    2,工作便条

      在公司总是事情很多,大事小事每天有十几件很正常,可惜记性不太好,如果不记下来,总会忘这忘那。所以除非遇到的是马上要处理的事,否则必然记下来,方式随便:碎纸片,记事本,札记等等,但要放在显眼的地方。


    3,日志

      学习的方法很多,其中最好的方法之一莫过于带着问题去学习,但问题解决了要记得把他记下来。初学者,或者比较笨拙的人(比如我自己)尤其应该这么做,目的是为了温故而知新。这样子可以在以后有时间的时候拿出来翻翻,由于是自己不会的东西,所以看起来很快;也正因为是自己不会的东西,看过之后就避免在犯同样的错误或问同样的问题。个人能力也正是在这点滴见积累起来的。个人在工作的时候,尤其是项目发布初期,总是会在一个地方记下该项目自发布运行时期遇到的所有问题,一则避免再犯,二则可以完善思路。

      很多新人刚开始总是问很多问题,有时候没人搭理自己就会觉得很委屈,其实是自己懒,经常问同样的问题才让人烦,所以要谨记这点。好记性不如赖笔头正是如此。     


    4,使用好办公软件

      上面说了几项,总结为一句话就是要记东西,这里就以此举例——使用好OutLook。个人觉得工作中有OutLook就足够了,完全用不着别的软件。OutLook提供了邮件,便条,任务,日历等多种功能,即实用又方便,何乐而不为呢?!本人目前OutLook里邮件自动分了N类,任务列表天天有亮有灰,每天早上上班,从来不用为今天干嘛而发愁,因为9:30有自动提醒。

      当然,如果你用别的办公软件也行,总之公司有的要用起来,没有的就弄个D版的用起来。


    5,强大的小工具:计算器,画图,记事本...

      也许你看到上面的名字觉得有点逗,其实很实在。本人电脑任务栏上必然有这些工具,随点随用,不亦乐乎。相信工作几年的人应该有此体会,刚入行的以后慢慢就知道了。

      以画图举例,说到截图,也许你会说Snagit,它是强大,但点来点去麻烦的很,还倒不如直接PrintScreen+Ctrl+V方便——平时又不需要去演示,谁需要截的那么细致啊。

      还有个记事本,就强大了,有心情的时候完全可以用记事本写代码假装高人,Word是很强大,但能写代码么?嘿嘿。平时灵光一闪有个绝好的点子,用记事本记下就记下来,不会丢掉;换做其他,恐怕工具还没打开,点子没了,郁闷就来了。


    6,帮助别人,向他人学习

      向他人学习,很多人都能做的到,实际未必。事实上如果你面前有个牛人,好学的你自然会向他请教学习,这只能算是好学的一小部分。因为跟你差不多的和比你差的总是占大部分。

      俗话说:“三个臭皮匠,顶个诸葛亮”,并不是说三个臭皮匠加起来就真的比诸葛亮厉害,而是说每个人都有可取之处,世上没有十全十美的人。就算你是公司的首席架构师又如何,总有你不会的东西。所以遇到跟你差不多的人,尤其是有些微妙的竞争关系的人,不要不服,一定虚心向人学习,这样子有可能你学到了他会的,而他没有学到你会的,结果你就真的超过了他。

      通常帮助别人时你一定在某一方面比别人强,这时也许你感觉很舒服,那人也很感激你。这时你要注意多些赠品,比如帮他检视代码啊,指出不足啊,最后一定发掘他的优点,顺便看看自己有没有。这样子既帮了别人,又帮了自己,只有自己知道是双赢并窃喜,结束时还可以故作大方地说“不客气”或者“不用找零了”!


    7,贪多嚼不烂

      上次有个新人说他现在要学习HTML+CSS+JavaScript+Asp.NET+C#+SQLServer,感觉学不过来,问我该怎么办。我说丢掉几个,他说学了一些,丢掉觉得可惜,又说有人给他的工作就需要这些,我还说丢掉大部分,主学一个,辅学另一个做调节,其他当兴趣;如果有人催,就说自己不会。最后他又说他问了好几个工作过的人,答案都这样。我说这就对了,贪多嚼不烂,听我们的,没有错。

      很多人经常会接触的很多东西,好奇心促使他什么都想学,他就同时什么都学,结果什么也学不会。人的精力毕竟有限,所以同时只能学习一门技术,能力好的可以学两门。其实,以我自己的经验来看,如果学精了一门,与之类似的技术,就算你根本都没接触过,你也可以声称自己精通它。这不是吹牛,所谓万变不离其踪。对于一门基础,只知万变顶多算入门;知其踪就可算精通了。然后遇到大同小异的东西,知其根难道还怕不知其表么?!

      举个例子,C#与Java之争由来已久,每次都口水漫天,这只能说大多数人都很水。真正懂C#或Java的人不会互喷(因为他都懂了,虽然他可能没用过C#或Java)——你见过C#或Java之父相互口水的么?!

    

    8,总结

      好了,今天就到这里。如果你觉得有什么不妥的地方,请你多多指正。

    posted @ 2010-11-03 08:42 倪大虾 阅读(3999) 评论(58) 编辑
    摘要: 前言前段时间忙了一阵子Google Earth,这周又忙了一阵子架构师论文开题报告,现在终于有时间继续<WPF之路>了。先回忆一下上篇的内容,在《从HelloWorld到WPF World》中,我们对WPF有了个大概的了解,并了解了初学WPF时应该从哪些知识点入手。今天我们就从最基本的知识点之一布局系统来继续学习WPF,主要包括如下内容。 0,什么是布局1,基本元素—&md...阅读全文
    posted @ 2010-10-31 22:04 倪大虾 阅读(4537) 评论(35) 编辑
    摘要: 今天看到园子里周金根的《个人管理:程序员应不应该离职,我该何去何从呢?》一文,读完之后就想写出自己的观点——个人离职的第四个理由——挑战与经历!  周兄能在一家公司工作十年,这种经历想来不多,我自问自己做不到。而周兄给出了三个离职理由(职业方向,环境氛围,工资奖金)也很恰当,在赋以充分的说明,更引起了大家的共鸣。然而人生就是如此吗?!  我相信人与人...阅读全文
    posted @ 2010-10-18 22:06 倪大虾 阅读(3472) 评论(53) 编辑
    摘要: 前言  有人说到,学习任何一种编程最困难的部分是“Hello World”。这一看似乎很可笑,仔细想来却未必。平时很多我们自认为很简单的东西也许恰恰是最困难的东西,比如C#中的一些基本概念,我们天天都在用,可你真的都理解他们吗?!对很多人来说恐怕要打个问号了。  最近开始学习使用WPF,WPF是什么?网上有很多文章,在此就不赘述了。  一切还是从“Hello World”开始,然而因为有了上面的经...阅读全文
    posted @ 2010-10-17 21:54 倪大虾 阅读(2551) 评论(27) 编辑
    摘要: 前言  过去我的一个朋友常说,学习任何编程语言最困难的部分是运行“Hello World”,之后一切都很容易。多年以后,我才意识到他说的很对。学习设计模式的基本目标是要用它,尤其是帮助那些有扎实的OOP基础,而对设计模式很困惑的人在设计中应用它。我不会为不同设计模式写很全面的参考,但我希望这些文章能让你入门。设计模式与特定的语言无关。虽然我用C#写了很多示例,但我尽量避免一...阅读全文
    posted @ 2010-10-10 22:24 倪大虾 阅读(2310) 评论(11) 编辑
    摘要: 简介  在.NET中,委托,匿名方法和Lambda表达式很容易发生混淆。我想下面的代码能证实这点。下面哪一个First会被编译?哪一个会返回我们需要的结果?即Customer.ID=5.答案是6个First不仅被编译,并都获得正确答案,且他们的结果一样。如果你对此感到困惑,那么请继续看这篇文章。什么是委托?  现在你定义一个处理用户订单的购物车ShoppingCart类。管理层决定根据数量,价格等...阅读全文
    posted @ 2010-10-07 22:06 倪大虾 阅读(5664) 评论(36) 编辑
    仅列出标题  下一页