设计模式之策略模式(Strategy)

策略模式:

策略模式属于对象行为模式[GOF95]。其用意是针对一组算法,将每一个算法封装到具体共同缄口的独立的类中,从来是的他们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化

问题

    架设现在要设计一个贩卖各类书籍的电子商务网站的购物车(shopping cart)系统。一个简单的情就是把所有货品的单价乘上数量,但是实际情况肯定比这复杂,比如对不同的图书给与折扣的问题

解决方案

    1/把所有的业务逻辑都放在客户端里面。客户端利用条件选择语句决定使用哪一个算法。这样一来,客户端代码会变得复杂难以维护。

    2/客户端可以利用继承的办法在子类里面实现不同的行为,但是这样会使得环紧和行为紧密耦合在一起,使得两者不能单独演化。

    3/使用策略模式。策略模式把行为和环境分割开来。环境负责维持和查询行为类,各类算法则在具体的策略类(ConcreteStrategy)中提供。由于算法和环境独立开来,算法的增减,修改都不会影响环境和客户端。

    策略模式正是解决这个问题的系统化方法。当出现新的折扣或现有的折扣出现变化,只需要实现新的策略类,并在客户端登记即可。策略模式相当于“可插入式(Pluggable)的算法”。

    当准备在一个系统里使用策略模式时,首先必须找到需要包装的算法,看看算法是否可以从环境中分割开来,最后在考虑这些算法是否会在以后发生变化。

引进策略模式

    策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得他们可以互换。”

//环境类的源代码
using System;
using System.Collections.Generic;
using System.Text;

namespace StrategyPattern
{
    public class Context
    {
        private Strategy strategy;
    
        public void contextInterface()
        {
            strategy.strategyInterface();
        }
    }
}

//抽象策略类的源代码
using System;
using System.Collections.Generic;
using System.Text;

namespace StrategyPattern
{
    public abstract class Strategy
    {
        public abstract void strategyInterface();
    }
}
//具体策略类的源代码
using System;
using System.Collections.Generic;
using System.Text;

namespace StrategyPattern
{
    public class ConcreteStrategy : Strategy
    {
        public override void strategyInterface()
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}

策略模式的实现有以下注意的地方 1/经常见到的是,所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。当然这时候抽象策略角色必须要用java抽象类实现,而不能使用java接口 2/策略模式在每一个时刻都只能使用一个策略对象,但是有时候一个应用程序同时与几个策略对象相联系。换言之,在应用程序启动时,所有的策略对象就已经被创立出来,而应用程序可以在几个策略对象之间调换。

图书折扣的计算

using System;
using System.Collections.Generic;
using System.Text;

namespace StrategyPattern
{
    public abstract class DiscountStrategy
    {
        private float price;
        private int copies;

        public DiscountStrategy(float price, int copies)
        {
            this.price = price;
            this.copies = copies;

        }
    
        public abstract double calclateDiscount();

    }
}



using System;
using System.Collections.Generic;
using System.Text;

namespace StrategyPattern
{
    public class FlatTateStrategy : DiscountStrategy
    {
        private float price;
        private int copies;
        private float acmount;
        public FlatTateStrategy(float price, int copies)
        {
            this.price = price;
            this.copies = copies;
        }

        public float Amount
        {
            get
            {
                return this.acmount;
            }
            set
            {
                this.acmount = value;
            }
        }
    
        public override double calclateDiscount()
        {
            return copies * acmount;
        }
    }
}



using System;
using System.Collections.Generic;
using System.Text;

namespace StrategyPattern
{
    public class PercenttageStrategy : DiscountStrategy
    {
        private float percent;
        private float price;
        private int copies;

        public PercenttageStrategy(float price, int copies)
        {
            this.price = price;
            this.copies = copies;
        }

        public float Percent
        {
            get
            {
                return this.percent;
            }
            set
            {
                this.percent = value;
            }
        }
    
        public override double calclateDiscount()
        {
            return copies * price * percent;
        }
    }
}

在什么情况下应当使用策略模式 1/如果在一个系统里面有许多类,他们之间的却别仅在于他们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一中行为。 2/一个系统需要动态的在几种算法中选择一种。那么这些算法可以包装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一的接口,由于多太性原则,客户端可以选择用任何一个具体算法类,并持有一个数据类型的抽象算法类的对象。 3/一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复杂的和算法有关的数据。 4/如果一个对象有很多行为,如果不用适当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大史住在大前端

野生前端的数据结构基础练习(8)——图

图是由边的集合和点的集合组成的。如果图的边有方向(或者说图中的顶点对是有序的)则成为有向图,如果边没有方向则称为无向图。

11430
来自专栏软件开发 -- 分享 互助 成长

散列表(哈希表)

序言: 如果将一系列的记录按照关键字的某种函数存储,那么在查找某个数据的时候就可以直接通过关键字计算出来了,而不在需要“比较”,这样会非常高效,这就是散列技术。...

20080
来自专栏Play & Scala 技术分享

Scala Macro 现状介绍

41450
来自专栏CreateAMind

pytorch初体验

一部分的内容在2017年1月18日Facebook发行的PyTorch相比TensorFlow、MXNet有何优势? - 罗若天的回答 - 知乎 已有。

15810
来自专栏Golang语言社区

麻将游戏数据结构和AI算法

用休息时间零零散散写完了网络麻将游戏,感觉其中有不少值得记录的东西。 基础数据结构     数据结构确定决定了程序的开发难易程度,就像是游戏的骨架,对于电脑AI...

1.3K20
来自专栏人工智能LeadAI

Theano调试技巧

Theano是最老牌的深度学习库之一。它灵活的特点使其非常适合学术研究和快速实验,但是它难以调试的问题也遭到过无数吐槽。其实Theano本身提供了很多辅助调试的...

1.2K90
来自专栏take time, save time

你所能用到的无损压缩编码(二)

     上个月项目荷兰大佬要检查,搞的我想写的东西不断推迟,现在检查完了,我决定继续把我想写的这整个一个系列写完,上一次写的是最简单的无损编码行程编码,这一次...

38890
来自专栏PPV课数据科学社区

【学习】《R实战》读书笔记(第二章)

“读书会是一种在于拓展视野、宏观思维、知识交流、提升生活的活动。PPV课R语言读书会以“学习、分享、进步”为宗旨,通过成员协作完成R语言专业书籍的精读和分享,达...

37390
来自专栏Rovo89

UML类图的学习笔记

12630
来自专栏代码永生,思想不朽

utf8中文字符串的多模式匹配算法的优化

上个月接触到了我组的一个关于在海量文本中匹配字符串业务。读源代码时发现一些问题,并针对这些问题做了优化工作,效果非常明显。

58930

扫码关注云+社区

领取腾讯云代金券