案例分析:设计模式与代码的结构特性
使用策略模式,用python实现一个淘宝优惠策略,输入原价,输出优惠之后的价格。
策略模式:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化,在对象中封装算法是策略模式的目的。
模式的主要参与者是策略对象(这些对象中封装了不同的算法)和它们的操作环境。
策略模式应用的关键点在于为策略和它的环境设计足够通用的接口,以支持一系列的算法。你不必为了支持一个新的算法而改变策略或它的环境。
需要换行功能的客户程序如果直接包含换行算法代码的话将会变得复杂,这使得客户程序庞大并且难以维护, 尤其当其需要支持多种换行算法时问题会更加严重。
不同的时候需要不同的算法,我们不想支持我们并不使用的换行算法。当换行功能是客户程序的一个难以分割的成分时 ,增加新的换行算法或改变现有算法将十分困难。
我们可以定义一些类来封装不同的换行算法,从而避免这些问题。一个以这种方法封装的算法称为一个策略。
存在以下情况时使用策略模式:
许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。
算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
一个类定义了多种行为 , 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的策略类中以代替这些条件语句。
双十一淘宝促销策略:
1:直接打折,原价300元,现价六折,180元销售,这种打折的方式是最简单明了的,消费者也很容易理解。
2:满减:满100元减40元,满200减90元,满300元减150元。
3:满150元,高于150元打5折。
类图如下:
使用抽象类,将IStrategy作为抽象类,构建了三个类,ReduceStrategy,RebateStrategy,PromotionalStrategy继承IStrategy,其中包括通过原价来计算优惠之后价格的realPrice方法和获得优惠策略名的strategyName方法。
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类往往用来表征对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。
构建了Context类,其中包含所使用的的是哪种策略的strategy属性,同时包含设置属性的setStrategy方法,和开始计算的cul方法。
构建了Client类,其中包括用户的名字的name属性和提供的原价price属性,同时包括设置name的setname方法,设置price的setprice方法和printResult方法输出结果。
各模块之前存在数据耦合,耦合度较低,存在顺序内聚,内聚度较高。
全部代码如下:
from abc import ABC, abstractmethod class IStrategy(ABC): @abstractmethod def realPrice(self, consumePrice): pass @abstractmethod def strategyName(self): pass class RebateStrategy(IStrategy): #6折商品促销策略 @classmethod def realPrice(self, consumePrice): return consumePrice * 0.6 def strategyName(self): return "RebateStrategy" class PromotionalStrategy(IStrategy): #150以上打5折商品促销策略 @classmethod def realPrice(self, consumePrice): if consumePrice > 150: consumePrice = 150 + (consumePrice-150) * 0.5 return consumePrice def strategyName(self): return "PromotionalStrategy" class ReduceStrategy(IStrategy): #满100元减40元,满200减90元,满300元减150元商品促销案策略 @classmethod def realPrice(self, consumePrice): if consumePrice >= 100 and consumePrice < 200: consumePrice -= 40 elif consumePrice >= 200 and consumePrice <300: consumePrice -= 90 elif consumePrice >= 300: consumePrice -= 150 return consumePrice def strategyName(self): return "ReduceStrategy" class Context: def __init__(self, strategy = None): self.strategy = strategy def setStrategy(self, strategy): self.strategy = strategy def cul(self, consumePrice): realPrice = self.strategy.realPrice(consumePrice) print(('打折策略:{}\n打折前:{}\n打折后:{}').format(self.strategy.strategyName(self), consumePrice, realPrice)) class Client: def __init__(self, name = None, price = None): self.name = name self.price = price def setname(self, name): self.name = name def setprice(self, price): self.price = price def printResult(self): print(('用户名:{}').format(self.name)) self.context = Context() self.context.setStrategy(RebateStrategy) self.context.cul(self.price) self.context.setStrategy(PromotionalStrategy) self.context.cul(self.price) self.context.setStrategy(ReduceStrategy) self.context.cul(self.price) client = Client() client.setname('Tom') client.setprice(200) client.printResult()
执行过程为:实例化一个Client类,对象名为client,使用Client的setname方法,设置name属性,通过setprice方法,设置price,最后使用printResult方法,输出结果。
代码:https://github.com/lc120798654/gaoruan
原文地址:https://www.cnblogs.com/lclclclc/p/12003122.html
- 18.12 keepalived + LVS
- 学会JS只是知道了“是什么”,并不意味着你会用JS做什么
- Linux基础(day68)
- 启动zabbix 报错
- 深入理解C# 3.x的新特性(2):Extension Method[上篇]
- 深入理解C# 3.x的新特性(2):Extension Method[下篇]
- 19.13/19.14 配置邮件告警
- 19.12 添加自定义监控项目
- [原创]深入理解C# 3.x的新特性(3):从Delegate、Anonymous Method到Lambda Expression
- a=b=c,但a不等于c?这是什么鬼
- 为什么不是0,1,2,3,4?setTimeout的奇怪问题
- Linux基础(day67)
- 深入理解C# 3.x的新特性(5):Object Initializer 和 Collection Initializer
- 19.10 处理图形中的乱码
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- pandas+PyQt5轻松制作数据处理工具
- Python高效编程之88条军规(1):编码规范、字节序列与字符串
- 这是一份 pip 常用命令小结~
- 太震撼了,我用python画出全北京的公交线路动图
- 小伙Python爬虫并自制新闻网站,太好玩了
- TRTC Android端开发接入学习之视频会议(八)
- MySQL锁都分不清,怎么面试进大厂?
- Kubernetes Controller高可用诡异的15mins超时
- 这几项超好用的云开发扩展能力,别说你还不知道!
- Ubuntu上一键卸载安装mysql脚本
- Python-批量修改图片全部颜色,批量修改图片的指定颜色,马甲包一键换主题UI
- 【SpringBoot DB 系列】h2databse 集成示例 demo
- MySQL 案例:analyze,慢查询,与查询无响应
- 万字图解Java多线程
- 金九银十要来了?不要慌,这些Android BAT高级面试题刷一刷