(转帖)小菜编程成长记(八 用“策略模式”是一种好策略) _sap 策略不好用-程序员宅基地

技术标签: C#学习  算法  华为  作业  编程  杀毒软件  设计模式  

小菜次日来找大鸟,说:“《深入浅出设计模式》的第一章我看完了,它讲的是策略模式(Strategy)。 『策略模式』定义了算法家族,分别封装起来,让它们之间可以互相替换, 此模式让算法的变化, 不会影响到使用算法的客户。看来商场收银系统应该考虑用策略模式?”
      “你问我?你说呢?”大鸟笑道,“商场收银时如何促销,用打折还是返利,其实都是一些算法,用工厂来生成算法对象,感觉是不是很怪?而最重要的是这些算法是随时都可能互相替换的,这就是变化点,而 封装变化点是我们面向对象的一种很重要的思维方式。”

       策略模式的结构 (源自吕震宇 博客)
       


      这个模式涉及到三个角色:

 

  • 环境(Context)角色:持有一个Strategy类的引用。
  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

      “我明白了,”小菜说,“我昨天写的CashSuper就是抽象策略,而正常收费CashNormal、打折收费CashRebate和返利收费CashReturn就是三个具体策略,也就是策略模式中说的具体算法,对吧?”


      “是的,那么关键就在于Context以及客户端程序如何写了?去查查资料,研究后把代码写出来给我看。”大鸟鼓励道。
      “好的,我一定很快写出来给你看!”小菜很兴奋。

        过一小时后,小菜给出商场收银程序的第四份作业。
CashContext类代码如下:

 

    
    
// 收费策略Context
     class  CashContext
    
{
        
//声明一个现金收费父类对象
        private CashSuper cs;

        
//设置策略行为,参数为具体的现金收费子类(正常,打折或返利)
        public void setBehavior(CashSuper csuper)
        
{
            
this.cs = csuper;
        }


        
//得到现金促销计算结果(利用了多态机制,不同的策略行为导致不同的结果)
        public double GetResult(double money)
        
{
            
return cs.acceptCash(money);
        }

    }

客户端主要代码如下:


       
double  total  =   0.0d ; // 用于总计
         private   void  btnOk_Click( object  sender, EventArgs e)
        
{
            CashContext cc 
= new CashContext();
            
switch (cbxType.SelectedItem.ToString())
            
{
                
case "正常收费":
                    cc.setBehavior(
new CashNormal());
                    
break;
                
case "满300返100":
                    cc.setBehavior(
new CashReturn("300","100"));
                    
break;
                
case "打8折":
                    cc.setBehavior(
new CashRebate("0.8"));
                    
break;
            }

            
            
double totalPrices = 0d;
            totalPrices 
= cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
            total 
= total + totalPrices;
            lbxList.Items.Add(
"单价:" + txtPrice.Text + " 数量:" + txtNum.Text + " "+cbxType.SelectedItem+ " 合计:" + totalPrices.ToString());
            lblResult.Text 
= total.ToString();
        }

实现的界面同之前一样(可点击使用)

 


       “大鸟,我用策略模式是实现了,但有些疑问,用了策略模式,则把分支判断又放回到客户端来了,这等于要改变需求算法时,还是要去更改客户端的程序呀?”
       “问得好,如果不是因为前面有工厂的例子,再来通过你的思考写出的这个策略模式的程序,你就问不出这样的问题的。”大鸟很开心,继续讲道,“最初的策略模式是有缺点的,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。”
        “那还不如工厂模式好用,至少要增加促销或改进打折额度时,不用去大改界面,而现在,界面程序要承担的责任还是太大。没有体现你说的封装变化点的作用呀。”小菜疑问多多。
       “就目前而言,的确是这样,这样的程序确实还是不够完善,要改的地方还很多。”大鸟说道,“不过正所谓病毒时间长了会有变种,杀毒软件本身也会随着病毒的变化而升级改良,如果我们对策略模式做一些改进,引入一些新的技术处理方式,就可以避免现在的这种耦合了。小菜,又有新的东西要学了,好好加油呀!”
      “大鸟,谢谢你,,你总是让我带着问题去思考,而不是直接说答案,我觉得这样学习进步很快,也不觉得设计模式很难了。” 
      “,用不着这么客气,我只是觉得,没有人是天生就牛X的,有一些所谓的技术牛人总会在人面前说什么,‘你连这都不懂’,‘这还不简单了,你够笨的’等等说词。给人感觉他非常聪明,天生就会的样子,其实他在之前也不知走过多少弯路,犯过多少错,或许他之前也被更早的牛人羞辱过,所以再继续把羞辱传给后人。”大鸟有些激动。
       小菜小心的说道:“大鸟,你是不是也曾经被人羞……”
       “哈哈,马云曾说过,男人的胸怀是被冤枉撑大的!天天在这行当里混,阅人无数,被羞辱也是正常的事了。问题在于是不是头脑清醒,自己不能放弃呀。所以我希望能真正的帮助初学者成长,而不是去显示牛气充当狂人。小菜,记住,学习一定是一个自己感悟的过程,而程序员的感悟就是自己写程序做项目,通过实践再学习,最终升华为牛人。
      “嗯,我记住了,不过到底如何改良策略模式呢?”
       大鸟微笑不语

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Oneil_Sally/article/details/2814086

智能推荐

android adb 进程端口号被占解决方法_adb进程的端口被占用-程序员宅基地

文章浏览阅读568次。1、查看adb 的进程端口号是什么,输入命令 adb nodaemon server 显示端口号2、查看端口号对应的进程pid ,输入命令 netstat -ano 查看对应的端口号的进程号3、查看进程号对应的进程名称或结束进程 tasklist|findstr "进程号" 或 taskkill /f /pid 进程号 ..._adb进程的端口被占用

swing:为什么一个类里调用另一个类的panel不显示_swing freechart chartpanel 放到另外一个panel 显示不出来-程序员宅基地

文章浏览阅读2.7k次。这是我在论坛发的一个帖子,在一哥们儿提醒下解决了,拿出来分享一下 //这是index类,要在这个类里调用另外一个类的panelpublic class IndexFrame extends JFrame {private static final lo_swing freechart chartpanel 放到另外一个panel 显示不出来

SpringBoot,写完老板又让我转回后端_deprecated configuration property 'spring.http.enc-程序员宅基地

文章浏览阅读1.9k次。SpringBoot1:SpringBoot基础入门1-1:什么是SpringBoot1-2:什么是微服务1:SpringBoot基础入门1-1:什么是SpringBoot什么是Spring Spring是一个开源框架,2003年兴起的一个轻量级的Java开发框架,作者:Rod Johnson。 Spring是为了解决企_deprecated configuration property 'spring.http.encoding.charset

手把手教会你!如何快速在VSCode创建一个VUE项目|前端菜鸟进阶版_vscode怎么创建项目-程序员宅基地

文章浏览阅读5.4k次,点赞4次,收藏20次。等待几分钟,自动弹出浏览器界面如下图,如果没有自动弹出浏览器窗口,我们可以手动复制图中倒数第三行local的地址,打开浏览器粘贴到地址栏,回车测试我们是否成功创建了vue项目。什么是JS(JavaScript):我封装好一个函数,这个函数可以给其他人调用,这个就是一个js。4.运行输出下面这些代码,如果你不确定选项具体是什么,这里的y/n问题全部回车跳过即可。浏览器出现上图的界面,表示成功创建好一个vue项目啦,现在可以开始你的前端小项目之旅啦。桌面创建一个空的文件夹,在这里我将它命名为test1。_vscode怎么创建项目

Nodejs以blob流方式编写JSON转EXCEL文件的导出服务-程序员宅基地

文章浏览阅读1.1k次。先说下业务需求,1.JSON转Excel表必须用xlsx格式,2.前端不能使用关于excel转换的插件,3.不能在后台生成相应的文件 前端纯js只能生成xls格式的Excel,因为公司前端环境比较稳定,在前端不能使用其他Excel插件的情况下,只能在后台用插件进行相关操作。但是因为不能生成文..._node express blob

带着dd去探索Linux磁盘IO_sync direct-程序员宅基地

文章浏览阅读256次。前言:Linux磁盘I/O是Linux内核的重要组成部分,是Linux开发工程师,特别是Linux存储开发工程师必须了解的一课。掌握了这一课,在遇到磁盘I/O相关问题时便会得心应手,缺席了这一课,遇到它时便会觉得云里雾里。dd是Linux的一款简单易用又功能强大的文件拷贝工具,大家再熟悉不过了,今天就带着它一起去探索Linux的磁盘I/O知识吧。dd测试首先看一下一份dd的测试数据,先感受下不同参数下dd的测试结果,然后带着疑问再去探索其中的原由。从上面的测试结果可以看到,没有oflag的时候,_sync direct

随便推点

容器的线程安全性_c++ map是线程安全的吗-程序员宅基地

文章浏览阅读775次。容器的线程安全性_c++ map是线程安全的吗

解决echarts饼图文字过长显示不全及文字重叠的问题_echart 饼状图 文字长度-程序员宅基地

文章浏览阅读1.1w次,点赞9次,收藏20次。直接上代码series: [ { type: 'pie', clickable:false,       //是否开启点击 minAngle: 5,    //最小的扇区角度(0 ~ 360),用于防止某个值过小导致扇区太小影响交互 avoidLabelOverlap: true, //是否启用防止标签重叠策略 _echart 饼状图 文字长度

WPF  触发器绘制Datagrid自定义变色单元格_wpfdatagrid单元格里绘制不同的图形-程序员宅基地

文章浏览阅读801次。WPF 触发器绘制Datagrid自定义变色单元格 (资源)<Window.Resources> <!--<c:ErrorConverter x:Key="ErrorConverter"/>--> <c:SheetArr x:Key="SheetCols"/> <Style TargetT_wpfdatagrid单元格里绘制不同的图形

ColossalAI_colossal ai 应用场景-程序员宅基地

文章浏览阅读121次。现有其他方案通常需要分布式系统资深专家,手动对代码进行大规模重构和调优,Colossal-AI 的 ShardFormer 提供了开箱即用的多维并行和算子优化的能力,仅需数行代码即可使用,在单机 / 大规模集群上都能提供良好的性能。为了进一步提升开发和部署效率,Colossal-AI 团队还将上述系统优势与算力结合,提供 Colossal-AI 云平台,提供廉价算力和开箱即用的 AI 主流应用,包括对话大模型,多模态模型,生物医药等,现已开启内测。而对于预训练任务,以使用。新 Gemini 提供了。_colossal ai 应用场景

V2X basic info-程序员宅基地

文章浏览阅读351次,点赞6次,收藏7次。

StringUtils 工具_stringutils.getifblank-程序员宅基地

文章浏览阅读475次。<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency>实验室:_stringutils.getifblank