场景分析

我们在网上购买商品的时候,经常遇到各种打折优惠活动,不同的节假日或者时间优惠策略都不相同,如果让我们去实现,那么如何做呢?

常规做法是根据不同的优惠政策,使用if进行判断,写很多判断分支进行处理。类似下面这种。

        if (正常价格) {//具体优惠策略处理}else if (七折优惠){//具体优惠策略处理}else if (国庆节优惠){//具体优惠策略处理}else if (优惠策略4条件){//具体优惠策略处理}else{//具体优惠策略处理}复制代码

这种方式虽然可以完成功能,但是缺点很多

  • 优惠策略经常改动。那么每次改动都需要来修改这段代码块,违反开闭原则
  • 如果优惠策略非常多,那么就需要写很多判断分支,判断复杂
  • 需要优惠策略功能的客户程序如果直接包含换行优惠策略的代码的话将会变得复杂,这使得客户程序庞大并且难以维护, 尤其当其需要支持多种优惠策略算法时问题会更加严重

要想避免上面的问题,解决方案就是把每种优惠策略封装成单独的类,客户端需要使用哪个优惠策略,就切换到该策略即可。这就需要使用到我们今天讲解的策略模式,下面来具体看看。


定义

定义一系列算法,把它们一个个的封装起来,并且使他们可以相互替换。策略模式使得算法可独立于使用它的客户端而变化。

通过定义,我们可以发现策略模式完全就是为解决我们开头提到的问题而生的。文章开头的实现方式就是因为把算法耦合进了客户端才会导致一系列问题。策略模式就是把算法和客户端解耦,把算法独立出来,然后给这些算法提供一个抽象的接口,每个具体的算法去实现这个接口,客户端只需要面向接口编程,需要使用哪个具体的算法,就切换到该算法即可。这样以后无论如何修改、扩展算法,都不会影响客户端的实现。

下面就来看看具体的UML结构图


UML结构图及说明

image

注意到结构图里面引入了一个context上下文对象,这个对象主要是为了隔离客户端和具体算法。context持有一个具体的算法对象,然后调用这个具体算法。但是context把具体算法的选择交给客户端来执行,自己只是持有客户端选择的的具体算法,然后客户端调用context暴露的接口,context就去调用具体的算法执行功能。

这样客户端只需要动态切换算法,然后设置到context,就可以调用不同的算法。


代码实现

上面我们分析了如何使用策略模式来完成我们的需求,下面就来看看具体的代码实现。

1、定义算法接口

#import <Foundation/Foundation.h>@protocol strategyInterface <NSObject>-(NSInteger)calcPrice:(NSInteger)goodsPrice;@end复制代码

2、具体算法实现

#import <Foundation/Foundation.h>
#import "strategy.h"@interface NationalDayStrategy : NSObject<strategyInterface>@end
===================
#import "NationalDayStrategy.h"@implementation NationalDayStrategy-(NSInteger)calcPrice:(NSInteger)goodsPrice{return goodsPrice * 0.5 - 12;
}
@end复制代码

上面只实现了国庆节优惠策略,其他的策略类似,具体看demo。

3、实现context

#import <Foundation/Foundation.h>
#import "strategy.h"@interface Price : NSObject
@property(strong,nonatomic)id<strategyInterface> strategy;- (instancetype)initWithStrategy:(id<strategyInterface>)strategy;
- (NSInteger)quotePirce:(NSInteger)goodsPrice;
@end===================================#import "Price.h"@implementation Price- (instancetype)initWithStrategy:(id<strategyInterface>)strategy
{self = [super init];if (self) {self.strategy = strategy;}return self;
}-(NSInteger)quotePirce:(NSInteger)goodsPrice{return [self.strategy calcPrice:goodsPrice];
}
@end复制代码

4、测试

id<strategyInterface>  strategy = [NationalDayStrategy new];
Price *quote = [[Price alloc]initWithStrategy:strategy];
NSInteger quotePrice = [quote quotePirce:10002];
NSLog(@"处理后的商品价格为:%zd", quotePrice);复制代码

如果需要换成其他优惠策略,只需要做如下更改即可:

  id<strategyInterface>  strategy = [NationalDayStrategy new];
改成:id<strategyInterface>  strategy = [discountStrategy new];复制代码

5、说明

上面的实现过程,我们把本来的商品价格作为参数通过context传递到具体的算法。还有一种情况我们可以把context本身作为参数传递给具体算法,这样后者就可以在合适的情况回调context。


使用时机

  • 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一
    个类的方法。
  • 需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间 /时间权衡的
    算法。当这些变体实现为一个算法的类层次时 ,可以使用策略模式。
  • 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数
    据结构。
  • 一个类定义了多种行为 , 并且这些行为在这个类的操作中以多个条件语句的形式出现。
    将相关的条件分支移入它们各自的 strategy 类中以代替这些条件语句。

优缺点

  1. 相 关 算 法 系 列 strategy类层次为 context 定 义 了 一 系 列 的 可 供 重 用 的 算 法 或 行 为 。 可以使用继承提取出这些算法中的公共功能。

  2. 一个替代继承的方式。你可以使用继承提供另一种支持多种算法或行为的方法,首先直接生成一个 context 类 的 子 类 , 然后 给 它 以 不 同 的 行 为,但 这 会 将 行 为 硬 行 编 制 到context 中。而将 算法的实现与context的实现混合起来 , 从而使 context 难 以 理 解 、 难 以 维 护 和 难 以 扩 展 , 而 且 还不能动态地改变算法。最后你得到一堆相关的类 , 它们之间的唯一差别只是它们所使用的算法或行为的不同。而将算法封装在独立的 strategy 类中,使得你可以独立于其context改变它,使它易于切换、 易于理解、易于扩展。

  1. 消除了一些条件语句。strategy模 式 提 供 了 用 条 件 语 句 选 择 所 需 的 行 为 以 外 的 另 一 种 选 择。当不同的行为堆砌在一个类中时 , 很难避免使用条件语句来选择合适的行为。将行为封装 在一个个独立的 strategy 类 中 消 除 了 这 些 条 件 语 句 。

  2. 实现的选择 S t r a t e g y 模式可以提供相同行为的不同实现。客户可以根据不同时间 / 空间 权衡取舍要求从不同策略中进行选择。

  3. 客户必须了解不同的 S t r a t e g y。 本 模 式 有 一 个 潜 在 的 缺 点 , 就 是 一 个 客 户 要 选 择 一 个 合 适的 S t r a t e g y 就必须知道这些 S t r a t e g y 到 底 有 何 不 同 。 此 时 可 能 不 得 不 向 客 户 暴 露 具 体 的 实 现 问题。因此仅当这些不同行为变体与客户相关的行为时 , 才需要使用 S t r a t e g y 模式。

  1. 增加了对象的数目 。你需要为每个不同的具体的S t r a t e g y增加了一个新的类,这就增加了应用中的对象的数目。此时你可以将 S t r a t e g y 实 现为可供各 C o n t e x t共享的无状态的对象来减少这一开销。任何其余的状态都由 C o n t e x t 维护。C o n t e x t 在每一次对 S t r a t e g y 对象的请求中都将这个状态传递过去。共享的 S t r a g e y不应在各次 调用之间维护状态。 F l y w e i g h t 模式更详细地描述了这一方法。

Demo下载

策略模式Demo下载

设计模式系列8--策略模式相关推荐

  1. 设计模式初学者系列-策略模式 -------为什么总是继承

    设计模式初学者系列-策略模式                                                 -------为什么总是继承 模板方法的延续 这篇稿子是基于我的前一篇模板 ...

  2. 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...

  3. 大前端晋级系列之-策略模式

    谨代表自己的理解,有错误欢迎指出! 因为有jQuery的源码分析系列,所以尽量走jQuery的设计风格,便于理解. 为什么要使用策略模式? 举个例子,企业或者个人都要纳税,但是不同的国家税点自然是不一 ...

  4. 设计模式系列·抽象工厂模式

    前言 以小说的笔法写的设计模式系列文章,你绝对看得懂![首发于公众号:"聊聊代码"] 设计模式系列·王小二需求历险记(一) 设计模式系列·王小二需求历险记(二) 设计模式系列·封装 ...

  5. 设计模式入门(策略模式)

    [0]README 0.1)本文部分文字描述转自 "head first 设计模式",旨在学习 设计模式入门(策略模式) 的基础知识: 0.2)本文章节4和5的source cod ...

  6. Java设计模式系列--责任链模式(应用)

    原文网址:Java设计模式系列--责任链模式(应用)_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Java设计模式中的责任链模式的一些使用场景. 责任链模式的好处 符合单一职责原则 每个功能 ...

  7. 设计模式系列之建造者模式构建实体类

    设计模式系列之建造者模式(Build Pattern)构建实体类 模式定义 建造者模式属于23种设计模式中的创建型模式,可以理解为创建对象的一种很好的方法. 所谓建造者模式就是**将组件和组件的组件过 ...

  8. Java设计模式系列3-----装饰模式,策略模式,观察者模式

    1.装饰模式 装饰(Decorator)模式又叫做包装模式.通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案. package com.ibeifeng.news;public i ...

  9. 【设计模式实践系列】策略模式应用订单折扣方案

    策略模式 策略模式指的是一个类的行为或其算法可以在运行时更改,在不同的场景中,有不同的实现算法. 意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换. 主要解决:在有多种算法相似的情 ...

  10. Head First Design Mode(2)-设计模式入门(策略模式)

    该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动! 设计模式入门: 欢迎来到设计模式世界: 我们会看到设计模式的用途和优点,再看看关键的OO原则,通过实例来了解模式是如何运作的 ...

最新文章

  1. 放射科医生选择AI供应商的10大标准
  2. Linux系统监控之磁盘I/O篇
  3. html for 循环模板
  4. px4原生源码学习二--实时操作系统篇
  5. 天兔安装手册-第一篇文章
  6. GTADIR check object exist in another system
  7. 轨迹预测演变(第1/2部分)
  8. Android如何分析native代码,使用android-ndk-profiler对native代码进行性能分析
  9. 安全加密 - 加密算法 - 摘要算法 - 秘钥交换协议 - 量子加密
  10. SEO长尾理论,关键词需求覆盖理论
  11. 448. Find All Numbers Disappeared in an Array -- Python
  12. Java期末大作业-工资系统平台(实验报告内附代码)
  13. psj在计算机课程中什么意思,计算机运用基础教育实践
  14. 48个英语音标练习-海伦英语视频
  15. 深度学习之图像分类(十二)--MobileNetV3 网络结构
  16. Windows一键删除指定文件或文件夹
  17. java.lang.NullPointerException: null
  18. [转]9款适合大学生使用的个人知识管理(PKM)工具软件
  19. K8S相同后端存储在2个K8S集群PVC数据直接拷贝
  20. Win10_X64远线程注入dll(非CreateRemoteThread)

热门文章

  1. Gnuplot安装避坑
  2. 查询出某个表依赖于某个表的外键,进行遍历删除操作
  3. java判断两个int相等_Java 判断两个变量是否相等
  4. oracle闪回 分区,Oracle 闪回区(Oracle Flash recovery area)
  5. python 函数调用列表,函数调用列表的Python oneliner
  6. 本科计算机专业考北大软微,2022北京大学软微学院计算机智能科技考研必看经验指导(含复试解析)...
  7. array用法 numpy_关于Numpy Array的使用技巧整理
  8. python _、__和__xx__的区别
  9. spring中怎么访问MySQL过程_【FunnyBear的Java之旅 - Spring篇】7步连接MySQL
  10. python进程线程处理模块_python程序中的线程操作 concurrent模块使用详解