设计模式记录3之“策略者模式”

今天学习了《大话设计模式》中的策略者模式。

定义:策略模式就是用来封装算法的。在实践中,我们用它来封装几乎任何类型的规则,只要在分析过程中听到任何时间有任何不同的应用规则,就可以考虑使用策略者模式处理这种变化的可能性。

优点:1 定义了一系列可重用的算法和行为,其中用到的继承有助于取出这些算法中的公共功能;

        2  简化了单元测试,每个类都是一个单独的算法,可以外接一个自己的接口进行测试。

场景: 一个商场的收银系统,有时候是"正常收费",有时候"打八折",有"满300减20"......各种收银的可能性都有。于是在这里我们就可以用到"策略模式"。

思路:定义一个接口,定义所有的算法的接口。创建各种算法(正常收费,打八折.....都是算法) ,继承算法接口,实现具体的算法方法。创建策略模式类,根据条件指定实现哪一个算法的实例。创建客户端,只需要传入参数即可。上代码:

 Step 1:

 /// <summary>
    
/// 策略者模式
    
/// 定义算法接口
    
/// </summary>
    interface InterfaceStrategy
    {
       
void GetStrategy();
    }

step 2:

 /// <summary>
    
/// 算法A类继承接口
    
/// </summary>
    class StrategyA:InterfaceStrategy
    {
        
public void GetStrategy()
        {
            Console.WriteLine(
"继承了A类算法");
        }
    }

  
/// <summary>
    
/// 算法B类,继承接口
    
/// </summary>
    class StrategyB:InterfaceStrategy
    {
        
public void GetStrategy()
        {
            Console.WriteLine(
"实现了B类算法");
        }
    }

 step 3: 

class StrategyContext
    {
        InterfaceStrategy strategy 
= null;//算法接口,定义在外层
        /// <summary>
        
/// 策略这模式与简单工厂模式相结合
        
/// 根据调试决定实例化哪个算法
        
/// </summary>
        public StrategyContext(string type)
        {
            
switch (type)
           { 
               
case "A":
                   StrategyA a 
= new StrategyA();
                   strategy 
= a;
                   
break;
               
case "B":
                   StrategyB b 
= new StrategyB();
                   strategy 
= b;
                   
break;
               
default:
                   
break;
           }
        }

        
//执行这个方法的时候,strategy对象已经通过switch分支语句获得了具体的行为对象
        public void GetStrategyResult()
        {
            strategy.GetStrategy();
        }

    }

 step 4:

/// <summary>
        
/// 策略者模式
        
/// 客户端
        
/// </summary>
        
/// <param name="args"></param>
        static void Main(string[] args)
        {
            
string type="A";
            
//将算法参数传入StrategyContext中,构造函数实例化
            StrategyContext context = new StrategyContext(type);
            context.GetStrategyResult();
            Console.ReadLine();
        }

 输出结果根据传入的参数"type"决定实例化哪个算法的实例。

到这里,我也跟书中小菜一样,觉得跟简单工厂一样,都是在switch语句中实现的,简单工厂是根据条件判断实例化那一个对象,策略者模式是根据条件判断实现哪一个算法。总觉得两者差不多。思考中?

---------

题外话:反射

MSDN介绍:

反射提供了封装程序集,模块和类型的对象(Type类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有的对象获取类型并调用其方法或者访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。

 用静态方法GetType 从 Object基类派生的所有类型都继承该方法,获取变量类型的简单反射示例:

int i = 42;
System.Type type 
= i.GetType();
System.Console.WriteLine(type);

输入为:
System.Int32

 使用反射获取已加载的程序集的完整名称:

System.Reflection.Assembly o = System.Reflection.Assembly.Load("mscorlib.dll");
System.Console.WriteLine(o.GetName());

输出为:
mscorlib, Version
=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

 反射在策略模式中的应用:

对于以上的代码,需要改的有两个地方,一个地方是Step3,去掉繁琐的switch语句,用一个方法代替,上代码:

        /// <summary>
        
/// 利用反射机制
        
/// </summary>
        private InterfaceStrategy infaceStrategy;
        
public void setBehavior(InterfaceStrategy super)
        {
            
this.infaceStrategy = super;
            super.GetStrategy();
        }

另一个也是反射应用的关键,step 4,客户端应用:

            //利用反射机制实现CreateInstance("Strategy.StrategyB")中的参数动态的获取实例
            StrategyContext context = new StrategyContext();
            context.setBehavior((InterfaceStrategy)Assembly.Load(
"Strategy").CreateInstance("Strategy.StrategyB"));
            Console.ReadLine();

 这样的话输出结果是"实现了B类算法"。其中反射的重点是:

 

                Assembly.Load("程序集名称").CreateInstance("命名空间.类名称")                   

 

 此处客户端我是为了简单才这样写的,其中 CreateInstance("Strategy.StrategyB")的参数"命名空间.类名称"中的类名称,存储在XML文件中,然后在客户端中读取出来,这样当我们要用用哪个算法的时候就只需要更改XML就可以了。

 XML文件如下:

<?xml version="1.0" encoding="utf-8" ?> 
<CashAcceptType>
   
<type>
      
<name>A</name>
      
<class>StrategyA</class>
  
</type>
     
<type>
     
<name>B</name>
     
<class>StrategyB</class>
  
</type>
</CashAcceptType>
posted @ 2011-04-21 20:10  淹死的鱼  阅读(290)  评论(0编辑  收藏  举报