NOTE

6.8 策略模式

1. 定义 完成同一件事有多种不同的方式,根据不同的type选择不同的算法,用if else太恶心 与状态模式的区别在于策略模式每种策略都是为了完成同一件事,而状态模式则是为了完成不同的事 2. uml 3. Java 3.1. client 3.2. context 3.3. 策略 4. Gola

Software Architecture & Engineering创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 定义

完成同一件事有多种不同的方式,根据不同的type选择不同的算法,用if else太恶心

与状态模式的区别在于策略模式每种策略都是为了完成同一件事,而状态模式则是为了完成不同的事

2. uml

PlantUML 图表

3. Java

3.1. client

public class Client
{
    public static void main(String[] args)
    {
        double price = 100.0;

        StrategyContext context = new StrategyContext();

        //老客户少量
        context.setStrategy(new OldCustomerFew());
        context.getPrice(price);

        //新客户少量
        context.setStrategy(new NewCustomerFewer());
        context.getPrice(price);
    }
}

3.2. context

public class StrategyContext
{
    private Strategy strategy;

    public Strategy getStrategy()
    {
        return strategy;
    }

    public void setStrategy(Strategy strategy)
    {
        this.strategy = strategy;
    }

    public void getPrice(double price)
    {
        System.out.println(this.strategy.getPrice(price));
    }
}

3.3. 策略

public interface Strategy
{
    double getPrice(double price);
}
public class NewCustomerFewer implements Strategy
{
    @Override
    public double getPrice(double price)
    {
        return price * 0.95;
    }
}
public class NewCustomerMany implements Strategy
{
    @Override
    public double getPrice(double price)
    {
        return 0.9 * price;
    }
}
public class OldCustomerFew implements Strategy
{
    @Override
    public double getPrice(double price)
    {
        return price * 0.85;
    }
}

4. Golang

4.1. 策略

/*用户打折策略*/
type IStrategy interface {
	GetPrice(price float64) float64
}

//老用户打折多的策略
type OldCustomerMuchStrategy struct {
}

func NewOldCustomerMuch() *OldCustomerMuchStrategy {
	return &OldCustomerMuchStrategy{}
}

func (o OldCustomerMuchStrategy) GetPrice(price float64) float64 {
	return price * 0.5
}

//新用户打折少的策略
type NewCustomerMuchStrategy struct {
}

func NewNewCustomerFew() *NewCustomerMuchStrategy {
	return &NewCustomerMuchStrategy{}
}

func (o NewCustomerMuchStrategy) GetPrice(price float64) float64 {
	return price * 0.8
}

4.2. 策略管理器

/*策略管理器*/
type StrategyContext struct {
	strategy IStrategy
}

func NewStrategyContext() *StrategyContext {
	return &StrategyContext{}
}

func (s *StrategyContext) Strategy() IStrategy {
	return s.strategy
}

func (s *StrategyContext) SetStrategy(strategy IStrategy) {
	s.strategy = strategy
}

//打折
func (s *StrategyContext) GetPrice(price float64)  {
	fmt.Printf("折扣后的价格:%f\n", s.strategy.GetPrice(price))
}

4.3. client

func main() {
	price := 100.0
	strategyContext := 策略模式.NewStrategyContext()
	strategyContext.SetStrategy(策略模式.NewOldCustomerMuch())
	strategyContext.GetPrice(price)
	strategyContext.SetStrategy(策略模式.NewNewCustomerFew())
	strategyContext.GetPrice(price)
}

5. 实例

模板方法+简单工厂+策略模式

  • pb.go
package pb

type SwitchRoomReq struct {

}

type SwitchRoomRsp struct {

}
  • abstract_template.go
package template

import (
	"context"
	"fmt"
	"test/template/pb"
)

/*实现了IFetchDataService*/
type abstractFetchDataService struct {
	IFetchDataSteps //内部的处理步骤
	req             *pb.SwitchRoomReq
	rsp             *pb.SwitchRoomRsp
	basicInfo       interface{} //基础数据
	extraInfo       interface{} //额外数据
}

func (t *abstractFetchDataService) checkParam(ctx context.Context) error {
	fmt.Println("default checkParam")
	return nil
}

func (t *abstractFetchDataService) getBasicInfo(ctx context.Context) error {
	fmt.Println("default getBasicInfo")
	return nil

}

func (t *abstractFetchDataService) getExtraInfo(ctx context.Context) error {
	fmt.Println("default getExtraInfo")
	return nil

}

//newTemplate
func newTemplate(iSteps IFetchDataSteps) *abstractFetchDataService {
	return &abstractFetchDataService{IFetchDataSteps: iSteps}
}

/*模板方法固定的步骤*/
func (t *abstractFetchDataService) HandleRequest(ctx context.Context, req *pb.SwitchRoomReq, rsp *pb.SwitchRoomRsp) error {
	t.req = req
	t.rsp = rsp
	if err := t.IFetchDataSteps.checkParam(ctx); err != nil {
		return err
	}
	if err := t.IFetchDataSteps.getBasicInfo(ctx); err != nil {
		return err
	}
	if err := t.IFetchDataSteps.getExtraInfo(ctx); err != nil {
		return err
	}
	return nil
}
  • content_read_template_impl.go
package template

import (
	"context"
	"fmt"
)

const TypeContentReadService = 2

var contentReadServiceConstructorFunc fetchDataServiceConstructor = func() IFetchDataService {
	return NewFetchDataFromContentReadService()
}

func init() {
	GlobalServiceFactory.RegisterService(TypeContentReadService, contentReadServiceConstructorFunc)
}

/*content_read服务*/
type FetchDataFromContentReadService struct {
	*abstractFetchDataService
}

func (f *FetchDataFromContentReadService) checkParam(ctx context.Context) error {
	fmt.Println("checkParam")
	return f.abstractFetchDataService.checkParam(ctx)
}

func (f *FetchDataFromContentReadService) getBasicInfo(ctx context.Context) error {
	fmt.Println("getBasicInfo")
	return f.abstractFetchDataService.getBasicInfo(ctx)

}

//func (f *FetchDataFromContentReadService) getExtraInfo(ctx context.Context) error {
//	fmt.Println("getExtraInfo")
//	return f.abstractFetchDataService.getExtraInfo(ctx)
//
//}


//NewFetchDataFromContentReadService
func NewFetchDataFromContentReadService() *FetchDataFromContentReadService {
	service := &FetchDataFromContentReadService{}
	service.abstractFetchDataService = newTemplate(service)
	return service
}
  • factory.go
package template

import "fmt"

var GlobalServiceFactory = newServiceFactory()

//自定义func。用于创建service实例
type fetchDataServiceConstructor = func() IFetchDataService

//serviceFunc工厂
type serviceFactory struct {
	serviceMap map[int]fetchDataServiceConstructor
}

//newServiceFactory
func newServiceFactory() *serviceFactory {
	return &serviceFactory{serviceMap: make(map[int]fetchDataServiceConstructor)}
}

//根据service type获取service
func (s *serviceFactory) GetServiceByType(serviceType int) (IFetchDataService, error) {
	serviceConstructor, ok := s.serviceMap[serviceType]
	if ok {
		return serviceConstructor(), nil
	}
	err := fmt.Errorf("GetServiceByType: serviceType %v invalid", serviceType)
	return nil, err
}

//注册serviceType和serviceConstructor
func (s *serviceFactory) RegisterService(serviceType int, serviceConstructor fetchDataServiceConstructor) {
	s.serviceMap[serviceType] = serviceConstructor
}
  • itemplate.go
package template

import (
	"context"
	"test/template/pb"
)

/*对外提供获取数据列表的接口*/
type IFetchDataService interface {
	HandleRequest(ctx context.Context, req *pb.SwitchRoomReq, rsp *pb.SwitchRoomRsp) error
}

/*内部的处理步骤*/
type IFetchDataSteps interface {
	//检查参数
	checkParam(ctx context.Context) error
	//获取基础数据
	getBasicInfo(ctx context.Context) error
	//获取额外数据
	getExtraInfo(ctx context.Context) error
}
  • template_test.go
package template

import (
	"context"
	"testing"
)

func TestTemplate(t *testing.T) {
	service, _ := GlobalServiceFactory.GetServiceByType(TypeContentReadService)
	service.HandleRequest(context.Background(), nil, nil)
}
//输出
checkParam
default checkParam
getBasicInfo
default getBasicInfo
default getExtraInfo