设计模式学习实践---策略模式(Strategy Pattern)

简介:

   看<<Head First设计模式>>有一段时间了,感觉总是这样看的话收获并不多,由于并没有在实践中应用所以才会比较枯燥,容易看了就忘.并没有实际掌握.就象以前看其它的设计模式的书一样,看了就只是看了,最后回忆起来只是几个模式的大致样子.所以从今天开始打算结合在开发过程中遇到的相应的模式,记录下来,深入理解.
      声明一下:只能保证原创和认真思考.不敢保证质量和水平,但求能够给看的人带来收获.
      策略模式(Strategy Pattern)属于对象行为型模式,体现了两个非常基本的面向对象设计的基本原则:封装变化的概念;编程中使用接口,而不是对接口实现。

定义:
         定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。每一个算法封装到具有共同接口的独立的类中,策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。
结构:
 
  应用:
  在asp.net的分层的框架开发中,经常需要在某一层使用和另外一个层次相关的东西,这样造成了耦合,对应用程度的扩展性造成了影响.前段时间在开发产品的时候,在业务层经常需要获取或者是保存当前用户信息的操作,这样的操作如果在Controller层的话还好,在业务层就有些头疼.毕竟整个产品框架是想业务层不能局限于WebFrom,存储方式也不能局限于Session,Cookie或者是静态变量.( 注:遇到这样的问题,最好是先考虑了是不是设计出了问题).
NewOrder
public Order NewOrder()
{
var order =new Order();
order.OrderID = Guid.NewGuid().ToString();
//读取状态(采购商和供应商)
order.ManufacturerReadState =0;
order.InnerCompanyReadState =0;
User currentUser = Session["CurrentUser"] as User;
InnerCompany ic = currentUser.Company as InnerCompany;
order.DeliveryLoc = currentUser.Company.ReceiveAd;
//默认为当前用户
order.Buyer = order.Creator = currentUser;
order.OrderState = OrderState.NewOrder;
return order;
}
一开始我们用了一个看起来很笨的方法,那就是传递UserID到业务层,但是这也造成了业务层很乱了,因为几乎每个业务方法都需要有个UserID参数...
NewOrder
public Order NewOrder(string UserID)
{
var order =new Order();
order.OrderID = Guid.NewGuid().ToString();
//读取状态(采购商和供应商)
order.ManufacturerReadState =0;
order.InnerCompanyReadState =0;
User currentUser = UserManager.GetUser(UserID);
InnerCompany ic = currentUser.Company as InnerCompany;
order.DeliveryLoc = currentUser.Company.ReceiveAd;
//默认为当前用户
order.Buyer = order.Creator = currentUser;
order.OrderState = OrderState.NewOrder;
return order;
}

      要解决的重点就是要把对用户操作和具体的应用环境解耦,并且又不要对应用程序造成比较大的修改和影响.策略模式的解决方案:(此解决方案源自spring.net)
   
      在IThreadStorage中定义了操作数据的接口(抽象策略对象),会有三个具体的实现CallContextStorage, HybridContextStorage和ThreadStaticStorage(具体策略对象),他们采用不同的方式来实现实现了接口.在LogicalThreadContext(环境对象)中,只引用抽象接口来完成对数据的操作.具体的实现方式对外面是封闭的.我们在开发中在LogicalThreadContext里直接创建了使用的具体策略对象,其实这里可以根据需要做成可配置,或者是利用ioc来实现更灵活些.
     代码实现:

IThreadStorage.cs
publicinterface IThreadStorage
{
///<summary>
/// Retrieves an object with the specified <paramref name="name"/>.
///</summary>
///<param name="name">The name of the item.</param>
///<returns>
/// The object in the current thread's context associated with the
/// specified <paramref name="name"/> or null if no object has been stored previously
///</returns>
object GetData(string name);

///<summary>
/// Stores a given object and associates it with the specified <paramref name="name"/>.
///</summary>
///<param name="name">The name with which to associate the new item.</param>
///<param name="value">The object to store in the current thread's context.</param>
void SetData(string name, object value);

///<summary>
/// Empties a data slot with the specified name.
///</summary>
///<remarks>
/// If the object with the specified <paramref name="name"/> is not found, the method does nothing.
///</remarks>
///<param name="name">The name of the object to remove.</param>
void FreeNamedDataSlot(string name);
}

 

CallContextStorage.cs
///<summary>
/// Implements <see cref="IThreadStorage"/> by using <see cref="CallContext"/>.
///</summary>
///<author>Erich Eichinger</author>
publicclass CallContextStorage : IThreadStorage
{
///<summary>
/// Retrieves an object with the specified name.
///</summary>
///<param name="name">The name of the item.</param>
///<returns>The object in the call context associated with the specified name or null if no object has been stored previously</returns>
publicobject GetData(string name)
{
return CallContext.GetData(name);
}

///<summary>
/// Stores a given object and associates it with the specified name.
///</summary>
///<param name="name">The name with which to associate the new item.</param>
///<param name="value">The object to store in the call context.</param>
publicvoid SetData(string name, object value)
{
CallContext.SetData(name, value);
}

///<summary>
/// Empties a data slot with the specified name.
///</summary>
///<param name="name">The name of the data slot to empty.</param>
publicvoid FreeNamedDataSlot(string name)
{
CallContext.FreeNamedDataSlot(name);
}
}


  

LogicalThreadContext.cs
///<summary>
/// An abstraction to safely store "ThreadStatic" data.
///</summary>
///<remarks>
/// By default, <see cref="CallContext"/> is used to store thread-specific data.
/// You may switch the storage strategy by calling <see cref="SetStorage(IThreadStorage)"/>.<p/>
///<b>NOTE:</b> Access to the underlying storage is not synchronized for performance reasons.
/// You should call <see cref="SetStorage(IThreadStorage)"/> only once at application startup!
///</remarks>
///<author>Erich Eichinger</author>
publicsealedclass LogicalThreadContext
{
///<summary>
/// Holds the current <see cref="IThreadStorage"/> strategy.
///</summary>
///<remarks>
/// Access to this variable is not synchronized on purpose for performance reasons.
/// Setting a different <see cref="IThreadStorage"/> strategy should happen only once
/// at application startup.
///</remarks>
privatestatic IThreadStorage threadStorage =new CallContextStorage();

///<summary>
/// Set the new <see cref="IThreadStorage"/> strategy.
///</summary>
publicstaticvoid SetStorage(IThreadStorage storage)
{
AssertUtils.ArgumentNotNull(storage, "storage");
threadStorage = storage;
}

private LogicalThreadContext()
{
thrownew NotSupportedException("must not be instantiated");
}

///<summary>
/// Retrieves an object with the specified name.
///</summary>
///<param name="name">The name of the item.</param>
///<returns>The object in the context associated with the specified name or null if no object has been stored previously</returns>
publicstaticobject GetData(string name)
{
return threadStorage.GetData(name);
}

///<summary>
/// Stores a given object and associates it with the specified name.
///</summary>
///<param name="name">The name with which to associate the new item.</param>
///<param name="value">The object to store in the current thread's context.</param>
publicstaticvoid SetData(string name, object value)
{
threadStorage.SetData(name, value);
}

///<summary>
/// Empties a data slot with the specified name.
///</summary>
///<param name="name">The name of the data slot to empty.</param>
publicstaticvoid FreeNamedDataSlot(string name)
{
threadStorage.FreeNamedDataSlot(name);
}
}

    这样,我们在Application_BeginRequest方法中记录当前用户,然后在业务层的一个方法里,获取当前用户:

Application_BeginRequest
protectedvoid Application_BeginRequest(Object sender, EventArgs e)
{
if (CookieHelper.UserID !=null)
{
if(LogicalThreadContext.GetData("UserID") ==null)
LogicalThreadContext.SetData("UserID", CookieHelper.UserID);
}
}

    

BaseManager
publicabstractclass BaseManager
{
publicstring CurrentUserID
{
get
{
object contextData = LogicalThreadContext.GetData("UserID");

if (contextData ==null)
returnnull;
else
return contextData.ToString();
}
}
}


    其它的两个实现和类图(及enterprise architect文件),请下载

分类: .NET

本文转自孤独侠客博客园博客,原文链接:http://www.cnblogs.com/lonely7345/archive/2008/10/20/1315190.html,如需转载请自行联系原作者
目录
相关文章
|
19天前
|
设计模式 算法
策略模式-大话设计模式
策略模式-大话设计模式
8 0
|
19天前
|
设计模式 存储 算法
设计模式学习心得之五种创建者模式(2)
设计模式学习心得之五种创建者模式(2)
15 2
|
19天前
|
设计模式 uml
设计模式学习心得之前置知识 UML图看法与六大原则(下)
设计模式学习心得之前置知识 UML图看法与六大原则(下)
12 2
|
4天前
|
设计模式 存储 缓存
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
8 0
|
13天前
|
设计模式 JavaScript 算法
js设计模式【详解】—— 策略模式
js设计模式【详解】—— 策略模式
12 0
|
17天前
|
设计模式 Java 中间件
深入探索Java设计模式:责任链模式解析与实践
深入探索Java设计模式:责任链模式解析与实践
14 0
|
17天前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)
|
19天前
|
设计模式 安全 Java
设计模式学习心得之五种创建者模式(1)
设计模式学习心得之五种创建者模式(1)
9 0
|
19天前
|
设计模式 数据可视化 程序员
设计模式学习心得之前置知识 UML图看法与六大原则(上)
设计模式学习心得之前置知识 UML图看法与六大原则(上)
10 0
|
5天前
|
设计模式 Go
Go语言设计模式:使用Option模式简化类的初始化
在Go语言中,面对构造函数参数过多导致的复杂性问题,可以采用Option模式。Option模式通过函数选项提供灵活的配置,增强了构造函数的可读性和可扩展性。以`Foo`为例,通过定义如`WithName`、`WithAge`、`WithDB`等设置器函数,调用者可以选择性地传递所需参数,避免了记忆参数顺序和类型。这种模式提升了代码的维护性和灵活性,特别是在处理多配置场景时。
41 8