策略模式

軟件設計模式

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中华民国交个人所得税”就有不同的算税方法。

策略模式:

  • 定义了一族算法(业务规则);
  • 封装了每个算法;
  • 这族的算法可互换代替(interchangeable)。

结构

 
Strategy Pattern in UML
 
Strategy pattern in LePUS3 (legend)

示例

#include <iostream>

using namespace std;

class StrategyInterface
{
    public:
        virtual void execute() = 0;
};

class ConcreteStrategyA: public StrategyInterface
{
    public:
        virtual void execute()
        {
            cout << "Called ConcreteStrategyA execute method" << endl;
        }
};

class ConcreteStrategyB: public StrategyInterface
{
    public:
        virtual void execute()
        {
            cout << "Called ConcreteStrategyB execute method" << endl;
        }
};

class ConcreteStrategyC: public StrategyInterface
{
    public:
        virtual void execute()
        {
            cout << "Called ConcreteStrategyC execute method" << endl;
        }
};

class Context
{
    private:
        StrategyInterface *_strategy;

    public:
        Context(StrategyInterface *strategy):_strategy(strategy)
        {
        }

        void set_strategy(StrategyInterface *strategy)
        {
            _strategy = strategy;
        }

        void execute()
        {
            _strategy->execute();
        }
};

int main(int argc, char *argv[])
{
    ConcreteStrategyA concreteStrategyA;
    ConcreteStrategyB concreteStrategyB;
    ConcreteStrategyC concreteStrategyC;

    Context contextA(&concreteStrategyA);
    Context contextB(&concreteStrategyB);
    Context contextC(&concreteStrategyC);

    contextA.execute();
    contextB.execute();
    contextC.execute();
    
    contextA.set_strategy(&concreteStrategyB);
    contextA.execute();
    contextA.set_strategy(&concreteStrategyC);
    contextA.execute();

    return 0;
}
//StrategyExample test application

class StrategyExample {

    public static void main(String[] args) {

        Context context;

        // Three contexts following different strategies
        context = new Context(new FirstStrategy());
        context.execute();

        context = new Context(new SecondStrategy());
        context.execute();

        context = new Context(new ThirdStrategy());
        context.execute();

    }

}

// The classes that implement a concrete strategy should implement this

// The context class uses this to call the concrete strategy
interface Strategy {

    void execute();
    
}

// Implements the algorithm using the strategy interface
class FirstStrategy implements Strategy {

    public void execute() {
        System.out.println("Called FirstStrategy.execute()");
    }
    
}

class SecondStrategy implements Strategy {

    public void execute() {
        System.out.println("Called SecondStrategy.execute()");
    }
    
}

class ThirdStrategy implements Strategy {

    public void execute() {
        System.out.println("Called ThirdStrategy.execute()");
    }
    
}

// Configured with a ConcreteStrategy object and maintains a reference to a Strategy object
class Context {

    Strategy strategy;

    // Constructor
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public void execute() {
        this.strategy.execute();
    }

}
using System;

namespace Wikipedia.Patterns.Strategy
{
  // MainApp test application
  class MainApp
  {
    static void Main()
    {
      Context context;

      // Three contexts following different strategies
      context = new Context(new ConcreteStrategyA());
      context.Execute();

      context = new Context(new ConcreteStrategyB());
      context.Execute();

      context = new Context(new ConcreteStrategyC());
      context.Execute();

    }
  }

  // The classes that implement a concrete strategy should implement this
  // The context class uses this to call the concrete strategy
  interface IStrategy
  {
    void Execute();
  }

  // Implements the algorithm using the strategy interface
  class ConcreteStrategyA : IStrategy
  {
    public void Execute()
    {
      Console.WriteLine( "Called ConcreteStrategyA.Execute()" );
    }
  }

  class ConcreteStrategyB : IStrategy
  {
    public void Execute()
    {
      Console.WriteLine( "Called ConcreteStrategyB.Execute()" );
    }
  }

  class ConcreteStrategyC : IStrategy
  {
    public void Execute()
    {
      Console.WriteLine( "Called ConcreteStrategyC.Execute()" );
    }
  }

  // Configured with a ConcreteStrategy object and maintains a reference to a Strategy object
  class Context
  {
    IStrategy strategy;

    // Constructor
    public Context(IStrategy strategy)
    {
      this.strategy = strategy;
    }

    public void Execute()
    {
      strategy.Execute();
    }
  }
}

ActionScript 3

//invoked from application.initialize
private function init() : void
{
    var context:Context;

    context = new Context( new ConcreteStrategyA() );
    context.execute();

    context = new Context( new ConcreteStrategyB() );
    context.execute();

    context = new Context( new ConcreteStrategyC() );
    context.execute();
}

package org.wikipedia.patterns.strategy
{
    public interface IStrategy
    {
	function execute() : void ;
    }
}

package org.wikipedia.patterns.strategy
{
    public final class ConcreteStrategyA implements IStrategy
    {
	public function execute():void
	{
	 trace( "ConcreteStrategyA.execute(); invoked" );
	}
    }
}

package org.wikipedia.patterns.strategy
{
    public final class ConcreteStrategyB implements IStrategy
    {
	public function execute():void
	{
	 trace( "ConcreteStrategyB.execute(); invoked" );
	}
    }
}

package org.wikipedia.patterns.strategy
{
    public final class ConcreteStrategyC implements IStrategy
    {
	public function execute():void
	{
	 trace( "ConcreteStrategyC.execute(); invoked" );
	}
    }
}

package org.wikipedia.patterns.strategy
{
   public class Context
   {
	private var strategy:IStrategy;
		
	public function Context(strategy:IStrategy)
	{
	 this.strategy = strategy;
	}
		
	public function execute() : void
	{ 
             strategy.execute();
	}
    }
}
<?php
class StrategyExample {
    public function __construct() {
        $context = new Context(new ConcreteStrategyA());
        $context->execute();

        $context = new Context(new ConcreteStrategyB());
        $context->execute();

        $context = new Context(new ConcreteStrategyC());
        $context->execute();
    }
}

interface IStrategy {
    public function execute();
}

class ConcreteStrategyA implements IStrategy {
    public function execute() {
        echo "Called ConcreteStrategyA execute method\n";
    }
}

class ConcreteStrategyB implements IStrategy {
    public function execute() {
        echo "Called ConcreteStrategyB execute method\n";
    }
}

class ConcreteStrategyC implements IStrategy {
    public function execute() {
        echo "Called ConcreteStrategyC execute method\n";
    }
}

class Context {
    var $strategy;

    public function __construct(IStrategy $strategy) {
        $this->strategy = $strategy;
    }

    public function execute() {
        $this->strategy->execute();
    }
}

new StrategyExample;
?>
@protocol Strategy <NSObject>

@required
- (void)print;

@end

@interface ConcreteStrategyA : NSObject<Strategy>
{
    
}

@end

@interface ConcreteStrategyB : NSObject<Strategy>
{
    
}

@end

@interface Context : NSObject
{
    id<Strategy> _strategy;
}

@property (nonatomic, assign) id<Strategy> strategy;

-(void)doIt;

@end


@implementation ConcreteStrategyA

- (void)print
{
    NSLog(@"Test01");
}

@end

@implementation ConcreteStrategyB

- (void)print
{
    NSLog(@"Test02");
}

@end

@implementation Context

@synthesize strategy = _strategy;

-(void)doIt
{
    [self.strategy print];
}

@end