一种简单清晰的 .NET 设计与实现方法 - 第一部分
一种快速简单的应用设计模式使用方法 - 第一部分。
引言
在设计模式和标准方面,有许多方法论可供软件开发生命周期参考。每个都需要解决以下问题:标准化、可重用性和可伸缩性。标准化方面包括编码标准、命名约定、注释、接口使用等。可重用性关注可扩展性以及作为组件模型运行或封装在 N 层方法中的灵活性。可伸缩性封装了对健壮编码、性能、数据使用和传输以及最终安全的强调。
当然,设计和开发应用程序涉及许多决策,即使是最简单的应用程序也需要在实施之前进行充分的设计工作。
在本文中,我将采用一个简单易懂的业务需求,并逐步完成设计和实现过程,在此过程中我将努力强调标准化、可重用性和可伸缩性。
背景
- 软件架构
- 面向对象编程
- 设计方法论 (RUP)
- UML
名称-值存储项目
用户需求
在此示例中,业务用户需要构建一个程序来存储名称-值对,例如 FirstName = Yang,其中 FirstName = 名称,Yang = 值。
名称值只能是字母数字值,并且等号周围的空格将被忽略。
存储需要基于 XML,并且 GUI 必须简单易用。
设计
用例
在这种情况下,用户需求简单明了。在与客户会面以收集更多信息之前,我们现在可以推导出有用的操作列表。我们还可以绘制用户与软件之间的高层交互。此时,我们还可以创建流程列表、应用程序的“必须”和“应该”项,这将提高可重用性和可扩展性。
可以绘制一个用例图来说明这一点
即使我们只有一个用户和一些非常简单的用例,这个过程也会迅速增长并变得更加复杂。通过分析用例,我们可以最大限度地降低进行功能更改和缩短开发时间的风险。
流程图
下一步是引入一些流程图设计。一个好的起点是针对每个用例,从中提取一个业务流程。同样,好的设计取决于验证的健壮性、可扩展性和错误处理。
扩展业务流程的一个好方法是 **通过对象公开事件**。这也可以提供拦截特定流程的方法,从而扩展应用程序。
错误处理和验证是紧密相连的。特定业务规则验证的结果应生成应用程序中受控的特定异常或结果。
让我们来看一个非常简单的创建名称-值对的流程
这个流程很简单,涉及特定的业务操作层次。业务层次的划分将为实现阶段提供线索,并减少实际项目设计的工作量。重要的是要关注流程中实体连接的方式,因为这最终会影响性能,并将用于计算攻击表面的安全性。
类图
健壮且可伸缩应用程序的关键在于其核心设计模型。由于大多数应用程序都处理信息,因此开发一个能够捕获所需信息的所有属性以及它们之间的交互和关系的模型至关重要。你对要捕获的内容了解得越多,模型就会越好,应用程序就会越健壮和可伸缩。
在这一阶段,你经常会面临挑战业务用户,询问为什么会捕获特定信息类型的决策。一个健壮的面向对象模型有时不遵循特定的业务模型,因为业务需求通常适用于非常范围中心和项目中心的数据集合。由于这种原因,我们的模型可能缺乏增长潜力和允许未来发展和可伸缩性的关键要素。尽可能挑战业务用户以增加范围或改变范围,以使项目能够充分发挥其潜力至关重要。通过遵循这种方法,我们可以为第一阶段以及未来的阶段以更少的时间交付更多内容。
接口的使用
下面是名称-值存储项目的类图。我没有简单地使用 `Hashtable` 或 `Dictionary` 作为我的实现,而是通过引入业务逻辑接口来启动项目。
using System;
using NameValueLib.BLL;
namespace NameValueLib
{
/// <summary>
/// Name value collection is used to manage a list of Name/Value pairs
/// </summary>
public interface INameValueCollection :
System.Collections.Generic.IList<NameValuePair>
{
/// <summary>
/// Raised on Adding new NameValuePair to the List
/// </summary>
event NameValueHandler InsertNameValuePair;
/// <summary>
/// Raised on Deleting NameValuePair from the list
/// </summary>
event NameValueHandler RemoveNameValuePair;
/// <summary>
/// Add a new Name value pair into the list given a single
/// patterned input in the format of [Name][delimiter][Value]
/// </summary>
/// <param name="NameValueString"></param>
void Add(string NameValueString);
/// <summary>
/// Removes all the name value pairs
/// </summary>
void Remove(NameValuePair[] nameValuePairs);
/// <summary>
/// Sort the list by Name ascendingly
/// </summary>
void SortByName();
/// <summary>
/// Sort the list by Value ascendingly
/// </summary>
void SortByValue();
/// <summary>
/// Sort the Name Value collection by a sort by and order
/// </summary>
void Sort(NameValueComparer.SortByType sortBy, bool ascending);
/// <summary>
/// Get the XML output of the list
/// </summary>
/// <returns></returns>
string GetXML();
/// <summary>
/// Save the List to an XML File
/// </summary>
/// <param name="FileName"></param>
void Save(string FileName);
}
}
如果你查看用例,你会注意到很多相似之处。通过分离实现和抽象原型,拥有这个接口为可扩展性留出了空间,并创建了标准化。根据规模和用户期望,我可以选择多种方式来实现此接口,无论是使用 `List<>`、`Dictionary<>` 还是自定义数据结构。
N层架构
通过采用 N 层方法,我们使应用程序能够跨域,可重用且可插入任何类型的应用程序,无论是 Web、Windows 还是服务应用程序。我们可以将其注册到 GAC,甚至 COM+。我们还为更安全的功能打开了一扇新门,而不会增加核心功能体的攻击面。N 层架构的许多优点都超过了其缺点。它现在是行业标准,并且是 SAAS 等下一代应用程序的桥梁。
该项目分为两层:业务逻辑层和在 Windows Forms 中完成的表示层。我可以轻松实现 Web 版本甚至控制台版本作为表示层。
关于标准化的一点。标准化使项目能够被同事理解,甚至将来你也可以理解,以便进行更改。编码标准和命名约定对于最大程度地减少查找和过滤所需的工作量至关重要。最好开发一个标准的项目布局(使用文件夹)以及一个类布局(使用命名空间)。这不仅有助于我们开发人员,有时还可以帮助 CLR 更有效地执行分组的代码。
验证
健壮的业务层应包含对输入变量的可靠验证。无论表示层多么安全,您都不应信任客户端。我在项目中使用的模式使用了 .NET 异常框架。为了有效地利用 .NET 异常框架,`NameValueException` 用于处理应用程序级别的业务逻辑验证异常。
..
public void Add(string NameValueString, string Delimiter)
{
string Errors;
// pre: validate
if (!NameValueValidator.DefaultValidator.ValidateNameValueInput(
NameValueString, Delimiter, out Errors))
throw new NameValueException(Errors);
try
{
// find delimiter position
int delPos = NameValueString.IndexOf(Delimiter);
// create new Name Value Pair
this.Add(new NameValuePair(NameValueString.Substring(0, delPos).Trim(),
NameValueString.Substring(delPos+Delimiter.Length).Trim(), Delimiter));
}
catch (NameValueException nex)
{
throw nex;
}
catch (Exception ex)
{
throw new NameValueException("Error Parsing Name Value Input.", ex);
}
}
..
事件和委托
事件和委托的使用提供了一种拦截应用程序触发器的方法,以及一种有效扩展业务逻辑的方法。
在此项目中,我创建了一个委托来处理通用的事件,例如标准数据集合的 `Add
()` 或 `Removed()`。
public delegate void NameValueHandler(object sender, NameValuePair NameValuePair);
排序
在 .NET 中有多种实现排序的方法。一种有效的方法是实现一个比较器并利用 `List<>` 对象的默认 .NET 快速排序。
/// <summary>
/// Comparer used to compare Name Value Pairs and for Sorting the NameValueCollection
/// </summary>
public class NameValueComparer
:IComparer<NameValuePair>
{
public enum SortByType: byte
{
name = 1,
value = 2
};
#region public propperties
private bool _ascending;
public bool Ascending
{
get
{
return this._ascending;
}
set
{
this._ascending = value;
}
}
private SortByType _sortBy;
public SortByType SortBy
{
get{
return this._sortBy;
}
set{
this._sortBy = value;
}
}
#endregion
#region constructors
public NameValueComparer():this(SortByType.name, true){}
/// <summary>
/// Create comparer
/// </summary>
/// <param name="sortBy"></param>
/// <param name="ascending"></param>
public NameValueComparer(SortByType sortBy, bool ascending)
{
this._sortBy = sortBy;
this._ascending = ascending;
}
#endregion
#region IComparer<NameValuePair> Members
/// <summary>
/// Compares x to y according to the sort and ordering
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public int Compare(NameValuePair x, NameValuePair y)
{
// pre:
if (x == null || y == null)
throw new NameValueException("Error Sorting Collection.");
if (this.SortBy == SortByType.name)
return this._ascending ? x.Name.CompareTo(y.Name) : y.Name.CompareTo(x.Name);
else if (this.SortBy == SortByType.value)
return this._ascending ? x.Value.CompareTo(y.Value) : y.Value.CompareTo(x.Value);
else
throw new NameValueException("Sort Type not found.");
}
#endregion
}
序列化
.NET 框架的一大改进是它能够轻松地进行序列化和反序列化。这些改编用于对象持久化、SOAP 等通信协议以及远程处理。
XML 序列化
敬请期待...
表示层
结论
即将推出……
关注点
您可以以任何可能的方式改进此项目并将其发送给我。我留下了一个接口的空字典实现,如果您有兴趣,可以随意进行。
历史
- 2008 年 4 月 24 日 - 文章初稿创建。