我读设计模式之策略模式(Strategy pattern)

     学习了工厂模式(简单工厂,工厂方法,抽象工厂)后,对设计模式的思想也算是有点头绪了,也更加明白了封装变化在软件设计中的重要性。今天读了策略模式,感觉还是非常实用的,尽管它的“规模”并不是很大。
 

     总的来说,策略模式给我印象是:在出现多个选项供选择的时候(if,else,switch)使用非常方便,避免了因为太多的选择出现难以维护的情况出现。

     吕震宇在Blog中给策略模式下了很好的定义:策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。使用策略模式可以把行为和环境分割开来。环境类负责维持和查询行为类,各种算法则在具体策略类(ConcreteStrategy)中提供。由于算法和环境独立开来,算法的增减、修改都不会影响环境和客户端。当政策出现变化时,只需要实现新的策略类,并在客户端登记即可。策略模式相当于"可插入式(Pluggable)的算法"。

     

     这个模式涉及三个角色:
     1.环境角色:基本上是在实例化策略类

     2.抽象策略角色:给所有策略提供统一的接口,可以用接口或者抽象类实现

     3.具体策略角色:包含具体的实现细节和算法

 

     根据我的理解,写下了下面这儿例子:根据当天的情况,选择具体的上班方式。

 

namespace Demo2
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            Console.WriteLine(
"请输入今天的情况:1 时间还早,2心情不错,3快迟到了");
            
int i = Convert.ToInt32(Console.ReadLine());
            context context 
= null;
            
switch (i)
            
{
                
case 1:
                    context 
= new context(new walkStrategy());
                    
break;
                
case 2:
                    context 
= new context(new runStrategy());
                    
break;
                
case 3:
                    context 
= new context(new onbusStratety());
                    
break;
                
default:
                    
break;
            }


            context.go();
        }

    }


    
class context
    
{
        IStrategy stra;
        
public context(IStrategy strategy)
        
{
            
this.stra = strategy;
        }

        
public void go()
        
{
            stra.duty();
        }

    }

    
interface IStrategy
    
{
        
void duty();
    }

    
class walkStrategy : IStrategy
    
{
        
public void duty()
        
{
            Console.WriteLine(
"今天时间还早,走着上班");
        }

    }

    
class runStrategy : IStrategy
    
{
        
public void duty()
        
{
            Console.WriteLine(
"今天心情不错,跑步上班");
        }

    }

    
class onbusStratety : IStrategy
    
{
        
public void duty()
        
{
            Console.WriteLine(
"今天快迟到了,坐车上班");
        }

    }

    
}

     按照一般的设计,我们完全可以在main方法中,写上条件判断语句,然后执行不同的方法就可以了。但是如果我们不希望client端了解具体的算法细节,而且多条件判断的维护是很困难的,性能也不咋地~。

     可以看到,上述例子中,虽然我们把具体的算法策略进行了抽象和封装,但是在client还是出现了判断语句,非常不爽。这种情况,已经不止一次碰到,用反射机制就可以轻松搞定:

static void Main(string[] args)
        
{       
            
string clsname = ConfigurationManager.AppSettings[0].ToString();
            IStrategy stra 
= Assembly.Load("Demo1").CreateInstance("Demo1."+clsname) as IStrategy;
            context context 
= new context(stra);
            context.go();
        }
app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  
<appSettings >
    
<add key ="classname" value ="runStrategy"/>
  
</appSettings>
</configuration>

 

     在吕老师和lovecherry的blog中提到了两种应用策略模式的场景:商场收银策略,ShowData策略。他们都体现了使用策略模式的时机:
     1.如果一个类有多种行为,并且在类内部通过条件语句来实现不同的行为的时候可以把这些行为单独封装为策略类

     2.如果系统需要选择多种算法中的一种并且希望通过统一的接口来获取算法的输出的话可以考虑策略模式。

     3.一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复杂的和只与算法有关的数据。

     4.如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念

     缺点显而易见:客户端必须知道每个策略都是做什么的,才能正确调用。

      【实践】
      之前用简单工厂模式实现的[针对不同的mvt生成不同的工厂具体类实现入库作业]入库作业,用策略模式也可以实现。其区别在于:
      1)简单工厂意在对象的创建,根据传递的mvt创建不同的“入库”对象;策略模式重在算法的封装。如果把一个mvt,看做一个策略,则此时可以“替代”。
      2)用简单工厂实现时,client需要知道工厂类和抽象类;而策略模式只需要知道策略类即可【可参考demo代码】,使得client彻底与具体实现分离,降低耦合。
      部分代码:
      简单工厂:

Code

      策略模式:

Code


Source Code:/Files/Ivan-Yan/StrategyPattern.rar


     参考:     

     http://www.cnblogs.com/zhenyulu/articles/82017.html

     http://www.cnblogs.com/lovecherry/archive/2007/10/13/923102.html

     大话设计模式:策略模式

posted on 2008-07-22 10:38  easy2Dev  阅读(358)  评论(0编辑  收藏  举报

导航