设计模式学习实践---策略模式(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,如需转载请自行联系原作者
目录
相关文章
|
14天前
|
设计模式 算法 C#
C#设计模式之策略模式
C#设计模式之策略模式
63 19
|
9天前
|
设计模式 算法 Java
Java中的设计模式:探索与实践
【8月更文挑战第10天】在Java开发中,设计模式是提升代码可读性、可维护性和扩展性的关键所在。本文将深入探讨几种常见的设计模式及其在实际项目中的应用,帮助开发者更好地理解和运用这些模式,以编写出更高质量的代码。
25 2
|
11天前
|
设计模式 算法 测试技术
[设计模式]行为型模式-策略模式
[设计模式]行为型模式-策略模式
|
1月前
|
设计模式 机器学习/深度学习 测试技术
设计模式转型:从传统同步到Python协程异步编程的实践与思考
【7月更文挑战第15天】探索从同步到Python协程异步编程的转变,异步处理I/O密集型任务提升效率。async/await关键词定义异步函数,asyncio库管理事件循环。面对挑战,如思维转变、错误处理和调试,可通过逐步迁移、学习资源、编写测试和使用辅助库来适应。通过实践和学习,开发者能有效优化性能和响应速度。
34 3
|
29天前
|
设计模式
iLogtail设计模式问题之iLogtail工厂模式下的实践流程是啥样的
iLogtail设计模式问题之iLogtail工厂模式下的实践流程是啥样的
|
2月前
|
设计模式 存储 算法
设计模式学习心得之五种创建者模式(2)
设计模式学习心得之五种创建者模式(2)
22 2
|
1月前
|
设计模式 存储 缓存
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
36 0
|
1月前
|
设计模式 JavaScript 算法
js设计模式【详解】—— 策略模式
js设计模式【详解】—— 策略模式
26 0
|
2月前
|
设计模式 Java 中间件
深入探索Java设计模式:责任链模式解析与实践
深入探索Java设计模式:责任链模式解析与实践
21 0
|
2月前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)