设计模式 - 策略模式(strategy pattern)

简介

场景

某个功能需要从多种算法中根据条件选择一种时,有两个方案:

  • 将所有算法硬编码到代码中,然后通过条件语句进行选择
  • 使用策略模式使系统可以灵活地选择算法,并可以灵活添加新算法

如果条件是固定的,比如根据星期几来选择算法,则可以通过条件语句硬编码。但是如果条件可能增加,可以使用策略模式。

模式定义

定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。

每个封装不同算法的类称为策略(Strategy)类。

模式特点

策略模式包含三个角色:

  • Context:环境类
  • Strategy:抽象策略类
  • ConcreteStrategy:具体策略类

设计模式 - 策略模式(strategy pattern)_第1张图片

优缺点

  • 策略模式将算法的定义和使用分离,符合开放封闭原则,易于扩展
  • 调用者可以自己决定使用哪个算法,灵活性提供的同时,使用难度也增大

PHP 代码示例

对于国际贸易,结算时,每个国家的税费计算方法都不同:

taxStrategy = $s;
	}
	
	public function calcTax() {
	    $context = array(
	        'fee' => 100,
        );
	    $val = $this->taxStrategy->calculate($context); // 多态调用
	    echo $val.PHP_EOL;
	}
}

$cn = new CNTax();
$so = new SalesOrder($cn);
$so->calcTax();

$fr = new FRTax();
$so = new SalesOrder($fr);
$so->calcTax();

Golang 代码示例

package main

import "fmt"

// 接口定义策略方法
type TaxStrategy interface {
    calculate(data map[string]float32) float32
}

// 策略一
type CNTax struct {}
func (cn *CNTax) calculate(data map[string]float32) float32 {
    return 0.1 * data["fee"]
}

// 策略二
type FRTax struct {}
func (fr *FRTax) calculate(data map[string]float32) float32 {
    return 0.3 * data["fee"]
}

type SalesOrder struct {
    taxStrategy TaxStrategy
}
func NewSalesOrder() *SalesOrder {
    return &SalesOrder{}
}
func (so *SalesOrder) setTaxStrategy(taxStrategy TaxStrategy) {
    so.taxStrategy = taxStrategy
}
func (so *SalesOrder) CalcTax(data map[string]float32) float32 {
    return so.taxStrategy.calculate(data)
}

func main() {
    data := map[string]float32{"fee":100}
    so := NewSalesOrder()
    
    // 根据需要实例化不同策略,并注入使用策略的类实例
    var cn TaxStrategy = &CNTax{}
    so.setTaxStrategy(cn)
    fmt.Println("CN fee is: ", so.CalcTax(data))
    
    var fr TaxStrategy = &FRTax{}
    so.setTaxStrategy(fr)
    fmt.Println("FR fee is: ", so.CalcTax(data))
}

你可能感兴趣的:(设计模式,strategy,pattern,策略模式)