首页 > 代码库 > ASP.NET 设计模式(转)
ASP.NET 设计模式(转)
Professional ASP.NET Design Patterns
为什么学习设计模式?
运用到ASP.NET应用程序中的设计模式、原则和最佳实践。设计模式和原则支持松散耦合、高内聚的代码,而这将提升代码的可读性、灵活性和可维护性。
对于那些已经有很好解决方法的任务,没有理由再去进行重复劳动。
著名建筑学家克里斯托弗·亚历山大 Christopher Alexander 曾经说过:
每种模式描述了一个在我们周围不断重复发生的问题,以及该问题解决方案的核心,这样你就可以一次又一次地使用该方案而不必做重复劳动。
约翰·列侬“没有问题,只有出路”
.NET开发人员学习的必要性
微软的RAD(Rapid application development)开发工具Visual Studio.NET快速开发表单式Web应用程序。通过简单的拖曳和所见即所得的应用程序设计界面,使得人们能够快速上手,一致的编程模型也有利于桌面应用程序开发者向Web应用程序开发转移。此外,由于编码模式与设计模式可以简单地进行切换,平面设计师在设计阶段就能够看到与运行时接近的界面,而不必频繁地运行调试模式或刷新网页,这使平面设计师能全程参与应用程序开发,从而提高了开发效率。然而,这种固化的表单式应用程序设计模式也存在先天不足。随着业务需求的变化和规模的不断增长,如果仍然把所有的业务逻辑放在后置代码中,将使代码日益臃肿,而且存在大量的重复代码。同时,这种Web表单式设计也不利于在应用程序中采用AJAX技术,很难在Web表单和Web服务程序之间共享代码。掌握书中提到的设计理念和实现工具,对于更好地理解ASP.NET MVC框架中的概念颇有益处。
模式与设计原则
设计模式是高层次的、抽象的解决方案模板。可以将这些模式视为解决方案的蓝本而不是解决方案本身。从中无法找到一种可以简单地运用到应用程序中的框架;相反,通常是通过重构自己的代码并将问题泛化来实现设计模式。
“四人组”(GoF)。他们收录了23种设计模式并将它们归纳为3组。
● 创建型模式(Creational):处理对象构造和引用。
● 结构型模式(Structual):处理对象之间的关系以及它们之间如何进行交互以形成更大的复杂对象。
● 行为型模式(Behavioural):处理对象之间的通信,特别是在责任和算法方面。
模式是描述复杂问题的解决方案的有效方式。如果具备设计模式的牢固知识,就可以与团队中的其他成员快速、顺畅地沟通,而不必纠结于底层的实现细节。模式是语言不可知的。通过学习模式而获得的知识将能够运用于具体编程时采用的任何优秀的面向对象语言。
设计模式的宗旨就是重用解决方案。当然,并非所有问题都是一模一样的,但如果能够将一个问题分解,并找出它与以前解决过的问题之间的相似之处,就可以运用这些解决方案。即使您认为自己遇到的问题是独特的,也应该可以通过将其分解成若干基本要素,将其泛化至一定程度,从而找出一种合适的解决方案。
设计模式的名称非常有用,这是因为它反映出该模式的行为和目的,并为人们在集思广益讨论解决方案时提供常用的词汇表。
陷阱:试图把设计模式运用到所做的每件事情,但最终取得的效果却与设计模式初衷(也就是让事情变得简单)相反。运用模式的较好方法是,通过识别正在试图解决的基本问题,来寻找适合它的解决方案。
设计原则
设计原则构成了设计模式赖以构建的基础。通过遵循经过验证的设计原则,自己的代码基会变得更加灵活、更能够适应变化,而且可维护性更佳。
1. 简约原则(KISS)
软件编程领域普遍存在的一个问题是需要把解决方案过度复杂化。KISS原则的目标就是让代码保持简洁但不要过于简陋,从而避免引入任何不必要的复杂度。
2. 不要重复自已(DRY)
DRY原则的目的是通过将公用的部分抽离出来放在一个单独的地方从而避免重复系统中的任何部分。这个原则不仅涉及代码而且包括系统中重复的任何逻辑。最终,系统中的任何一部分知识都应该只有一种表示形式。
3. 讲述而不要询问(Tell, Don‘t Ask)
“讲述而不要询问”原则体现了封装以及将责任指派到正确的类这两个思想。这个原则要求,应该告诉对象您希望它们执行什么动作,而不是询问有关该对象状态的问题然后由您自己决定希望执行什么动作。这个原则有助于匹配责任并避免类之间的紧密耦合。
4. 您不需要它(YAGNI)
YAGNI原则指的是只需要将应用程序必需的功能包含进来,而不要试图添加任何其他您认为可能需要的功能。测试驱动开发(TDD)就是一种坚持YAGNI原则的设计方法学。TDD的宗旨就是编写测试来验证系统的功能,然后只需要编写可让测试通过的代码即可。
5. 分离关注点(SoC)
SoC这一过程将软件分解为多项不同的功能,每项功能封装了可供其他类使用的唯一行为和数据。通常,一个关注点代表类的一项功能或行为。将程序划分成若干独立职责的做法显著提高了代码的重用程度、维护性和可测试性。
S.O.L.I.D.设计原则是一组针对面向对象设计的最佳实践。术语S.O.L.I.D.来自于Robert C. Martin(朋友们亲切地称呼他Bob大叔)的著作Agile Principles, Patterns, and Practices in C#中收集的5个设计原则的名称的首字母。
1. 单一责任原则(SRP)
SRP原则与SoC原则保持高度一致。它要求每个对象只应该为一个元素而改变而且只有一个职责关注点。遵循这个原则,就可以避免单体类(就像是软件领域的瑞士军刀)设计问题。使每个类均保持简洁,就可以提升系统的可读性和可维护性。
2. 开放封闭原则(OCP)
OCP原则要求类对于扩展应该是开放的,而对于修改应该是封闭的,这样应该就能够在不改变类的内部行为的情况下添加新功能并扩展类。这个原则努力避免破坏已有的类以及其他依赖它的类,因为这会在应用程序中造成bug和错误的涟漪效应。
3. 里氏替换原则(LSP)
LSP原则指出应该能够使用任何继承类来替代父类并且让其行为方式保持不变。这个原则与OCP原则保持一致:它确保继承类不会影响父类的行为,换句话来说,继承类必须可替代它们的基类。
4. 接口分离原则(ISP)
ISP原则关注的是将契约的方法划分成若干职责分组,并且为这些分组指派不同的接口,这样客户端就不需要实现一个庞大的接口和一堆它们并不使用的方法。这个原则背后的目的是:使用相同接口的类只需要实现特定的一组方法,而不是实现一个庞大的单体方法接口。
5. 依赖倒置原则(DIP)
DIP原则的宗旨是将自己编写的类与具体的实现隔离开来,让这些类依赖于抽象类或接口。它提倡面向接口(而不是实现)编程,这确保代码不会与某种实现紧密耦合,从而提高了系统的灵活性。
6. 依赖注入(DI)和控制反转(IoC)原则
与DIP紧密相关的是DI原则和IoC原则。DI通过构造器、方法或属性来提供底层类或从属类。配合使用DI原则,这些从属类可以被反转为接口或抽象类,这样就可以形成一个具有较高的可测试性和易于修改的松散耦合系统。
在IoC原则中,系统的控制流与过程式编程方法相比是反转的。这个原则的一个示例是IoC容器,它的作用是将服务注入到客户端代码,而不必让客户端代码指定具体的实现。在该实例中,控制反转指的是客户端获取服务的行为。
Fowler的企业设计模式
Martin Fowler的著作Patterns of Enterprise Application Architecture是有关如何构建企业级应用程序的最佳实践和模式的参考书。
1领域逻辑模式
组织业务逻辑的3种常见方法:Transaction Script(事务脚本)、Active Record(活动记录)及Domain Model(领域模型)。
1. Transaction Script
Transaction Script模式按照线性的、过程式方法来组织业务逻辑。它将细粒度的业务用例映射为细粒度的方法。
2. Active Record
Active Record模式按照一种能够紧密匹配底层数据结构的方式来组织业务逻辑,即表中表示数据行的对象。
3. Domain Model
Domain Model模式是对现实领域对象的抽象。同时对数据和行为建模。对象之间可以存在与真实领域相匹配的复杂关系。
2对象关系映射
支持持久化的基础设施代码所需的企业模式。
1. Unit of Work
Unit of Work(工作单元)模式用来维护一个由已经经过业务事务修改(添加、删除或更新)的业务对象构成的列表。然后,Unit of Work模式负责将这些发生变化的对象的持久化工作协调成为一个原子动作。如果出现问题,整个事务就会回滚。
2. Repository
Repository(资源库)模式大体上用于对象的逻辑集合,它们更为人知的名字叫做聚合(aggregate)。它充当业务实体的内存集合或仓库,完全将底层数据基础设施抽象出来。
3. Data Mapper
Data Mapper(数据映射器)模式用来从原始数据中提取信息以生成对象,以及将业务对象中的信息转换到数据库。业务对象和数据库彼此互不了解。
4. Identity Map
Identity Map(标识映射)模式监视每一个从数据库中加载的对象,确保所有对象只加载一次。当后面请求该对象时,在从数据库检索之前先检查标志映射。
5. Lazy Loading
Lazy Loading(惰性加载或延迟加载)模式将获取资源的过程推迟到真正需要用到该资源的时候。
6. Query Object
Query Object(查询对象)模式是GoF的Interpreter(解释器)设计模式的一种实现。查询对象充当一种从底层数据库中抽象出来的面向对象查询,它引用的是属性和类,而不是真正的表和列。通常,还需要使用一个翻译器对象来生成用于查询数据库的原生SQL语句。
Web表示模式
将领域和表示逻辑分离同时让表示层能够有效测试的模式。这些模式的任务都是将用于表示的逻辑关注点与业务逻辑关注点分离。ASP.NET表示需要所涵盖的模式有:
● Model-View-Presenter(模型-视图-表示器)。
● Model-View-Controller(模型-视图-控制器)。
● Front Controller(前端控制器)。
● Page Controller(页面控制器)。
Fowler著作中的其他企业模式
1. Null Object模式
Null Object(空对象)模式也称为Special Case(特殊情况)模式,它充当返回值而不是向调用代码返回null。空对象将与预期结果共享相同的接口或者从相同的基类继承而来,这样减少了在代码基中到处检查null情况的需要。
2. Separated Interface模式
Separated Interface(独立接口)模式要求将接口放在一个独立于具体实现的程序集或命名空间中。这确保客户端完全不知道具体实现,而且能够遵循面向抽象编程(而不是面向实现)以及依赖倒置原则。
3. Gateway模式
Gateway(网关)模式允许客户端通过一个简化的接口来访问复杂的资源。网关对象基本上将资源API包装成一个能够在应用程序中到处使用的单个方法调用。此外,它还隐藏了所有的API复杂性。
--------------------------------
TDD(Test-driven Development,测试驱动设计)并不像它的名称所言,它更多的是一种设计方法学而不是测试策略。这种设计方法学背后的主要思想是使用测试来塑造系统的设计。在创建软件解决方案时,首先编写一个导致测试失败的测试程序来断言某种业务逻辑。然后编写代码让测试通过。最终,通过重构来清理所有代码。这三步已经被人们称为红-绿-重构(red-green-refactor)。红和绿指的是测试框架分别用来显示测试通过和测试失败的颜色。
通过经历TDD流程,最终将得到一个带有一套可以确认所有行为的测试的松耦合系统。TDD的一个副产品是这些测试提供了一种描述系统能够做什么以及不能做什么的文档。因为测试属于系统的一部分,所以它绝不会过时,这与编写的文档和代码注释不同。
● Test Driven Development: By Example,Kent Beck著
● The Art of Unit Testing: With Examples in .NET,Roy Osherove著
● Professional Enterprise .NET,Jon Arking与Scott Millett合著(Wrox出版)
DDD(Domain-driven Design,领域驱动设计)是一组有助于构建反映对业务的理解并满足业务需求的应用程序的模式和原则。除此之外,它是一种思考开发方法学的全新方式。DDD的建模方式如下:首先通过全面理解真实领域来对真实领域建模,然后将所有的术语、规则和逻辑放到代码的某种抽象表示中(通常是以领域模型的形式)。虽然DDD并不是一种框架,但是它确实有一组构建块或概念可以整合到解决方案中。
● Domain-Driven Design: Tackling Complexity in the Heart of Software,Eric Evans著
● Applying Domain-Driven Design and Patterns: With Examples in C# and .NET,Jimmy Nilsson著
● .NET Domain-Driven Design with C#: Problem - Design -
BDD(Behavior-driven Design,行为驱动设计)被视为TDD与DDD合并的结果。BDD关注系统的行为而不仅仅是测试它。使用BDD时所创建的规范可以使用在真实领域中随处可见的语言,这能够让技术用户和业务用户同时受益。
采用BDD编写规范时产生的文档可以让读者了解系统在各种情况下表现什么样的行为,而不是简单地验证各个方法正在执行它们应该完成的工作。通过将DDD的若干方面与核心TDD概念有机融合,BDD将同时满足业务用户和技术用户的需求。可以使用标准的单元测试框架来执行BDD,但专门的BDD框架已经出现了,而且BDD即将成为下一个大事件。
怎样学习
名称和意图 反映该模式或原则的目的、用法、好处以及使用该模式的动机。
UML图
展示模式或原则的结构的图形化表示。图形化表示用来显示通用的解决方案模版以及其实现。
代码实现
如何选择和运用设计模式
●在不了解模式的情况下不能运用它们。首先扩大自己的知识面并采用从抽象到具体的方法来学习模式和原则。
●是否有必要引入设计模式的复杂性。需要衡量实现某种模式所需的时间与该模式能够带来的收益。谨记KISS原则。
●讲问题泛化,已更抽象的方式识别正在处理问题。了解每个模式和原则是如何编写的。并了解自己需要解决的问题是否符合特定模式或原则试图解决的问题。设计模式是高层次的激将法解决方案,试着把问题抽象,不要过于关注具体问题的细节。
●了解具有类似性质的模式以及同组中的其他模式。
●封装变化的部分。了解应用程序中什么可能发生变化。
●在选择好设计模式之后,确保在命名解决方案中的参与者使用该模式的语言及领域语言。FedExShippingCostStrategy 使用策略模式为不同的快递公司计价