# Strategy 模式简介

策略模式 (Strategy Pattern), 可以使一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于 行为型模式

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

# 运用场景分析

举个栗子:在软件开发中常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。如查找、排序等。

一种常用的方法是硬编码 ( Hard Coding ) 在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法当然也可以将这些查找算法封装在一个统一的方法中,通过 if...else... 或者 case 等条件判断语句来进行选择。这两种实现方法我们都可以称之为硬编码.

当然,如果需要增加一种新的查找算法,需要修改封装算法类的源代码;更换查找算法,也需要修改客户端调用代码。在这个算法类中封装了大量查找算法,该类代码将较复杂,维护较为困难

如果我们将这些策略包含在客户端,这种做法更不可取,将导致客户端程序庞大而且难以维护,如果存在大量可供选择的算法时问题将变得更加严重Strategy 就主要解决这类场景所带来的问题。

# 结构分析

让使用算法的环境类 ( Context ) 包含一个抽象类或者接口 ( Strategy ), 该抽象类有一个抽象方法指定如何调用算法,每个派生类按照需要实现算法。根据 Strategy 实现子策略类完成策略的封装,在客户端 ( Cilent ) 使用

Context 和策略对象 (具体某种策略的对象,如: ConcreteStrategyA ) 来演示 Context 在它所配置或使用的策略改变时的行为变化。

Statery_Pattern_UML

注意:在原型 Strategy 模式中,选择所用具体实现的职责由客户端 ( Client ) 对象承担,并转给 Strategy 模式的 Context 对象。

# Strategy 模式关键特征分析

  • 意图:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换,即可以根据上下文所处环境,使用不同的算法。
  • 主要解决:在有多种算法相似的情况下,使用 if...else... 所带来的复杂和难以维护
  • 何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为,每个类都是一个策略,每个策略都可以得到相同的结果,但是它们使用了不同的资源。
  • 如何解决:将这些算法封装成一个一个的类,任意地替换。
  • 关键代码:实现同一个接口。
  • 应用实例:
    1. 诸葛亮的锦囊妙计,每一个锦囊就是一个策略。
    2. 旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。
    3. JAVA AWT 中的 LayoutManager。
  • 优点:
    1. 算法可以自由切换。
    2. 避免使用多重条件判断。
    3. 扩展性良好。
  • 缺点:
    1. 策略类会增多。
    2. 所有策略类都需要对外暴露。
  • 使用场景:
    1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
    2. 一个系统需要动态地在几种算法中选择一种。
    3. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。如何让算法和对象分开来,使得算法可以独立于使用它的客户而变化?就是使用 Strategy 模式的目的。

# 具体实现

出行旅游:我们可以有几个策略可以考虑:可以骑自行车,汽车,做火车,飞机

每个策略都可以得到相同的结果,但是它们使用了不同的资源。选择策略的依据是费用,时间,使用工具还有每种方式的方便程度,具体实现如下。

Strategy_Pattern_TravelDempUML

# Step1: 创建一个接口

ITravelStrategy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StrategyPatternDemo_策略模式_
{
    // 出行方式的实现接口
    interface ITravelStrategy
    {
        void TravelAlgorithm();
    }
}

# Step2: 实现接口

实现三种具体的旅游出行可能采用的交通方式

AirPlaneStrategy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StrategyPatternDemo_策略模式_
{
    class AirPlaneStrategy : ITravelStrategy
    {
        public void TravelAlgorithm()
        {
            Console.WriteLine("AirPlane is routing means of transportation!");
        }
    }
}

BicycleStrategy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StrategyPatternDemo_策略模式_
{
    class BicycleStrategy : ITravelStrategy
    {
        public void TravelAlgorithm()
        {
            Console.WriteLine("Bicycle is routing means of transportation!");
        }
    }
}

TrainStrategy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StrategyPatternDemo_策略模式_
{
    class TrainStrategy : ITravelStrategy
    {
        public void TravelAlgorithm()
        {
            Console.WriteLine("Train is routing means of transportation!");
        }
    }
}

# Step3: 创建 Context (环境类)

Context.cs 聚合一个 Strategy 对象由客户端传参初始化动态调用算法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StrategyPatternDemo_策略模式_
{
    // 环境类,具体实现何种方式的职责 由客户端承担
    //(传入 travelStrategy )动态的使用封装的算法
    class Context
    {
        private ITravelStrategy travelStrategy = null;
        public Context(ITravelStrategy travelStrategy)
        {
            this.travelStrategy = travelStrategy;
        }
        public void TravelMethod()
        {
            travelStrategy.TravelAlgorithm();
        }
    }
}

# Step4: 创建客户端 Client

TravelClient.cs 使用 Context 来查看当它改变策略 Strategy 时的具体实现的行为

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StrategyPatternDemo_策略模式_
{
    class TravelClient
    {
        static void Main(string[] args)
        {
            // 飞机出行
            Context travelContext = new Context(new AirPlaneStrategy());
            travelContext.TravelMethod();
            // 骑自行车出行
            travelContext = new Context(new BicycleStrategy());
            travelContext.TravelMethod();
            // 坐火车出行
            travelContext = new Context(new TrainStrategy());
            travelContext.TravelMethod();
        }
    }
}

输出结果

AirPlane is routing means of transportation!
Bicycle is routing means of transportation!
Train is routing means of transportation!

# 样例代码下载地址

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Seiun 微信支付

微信支付

Seiun 支付宝

支付宝