• 书店会员销售系统(三)


    书店会员销售系统(三)
                         ――OORefactoring and Design Pattern
    本节目的:
    1.         学习使用Abstract Factory模式。
    2.         学习使用Factory Method模式。
    3.         使用重构手法。

    客户:  “你们前期的工作很不错,我们非常满意。”
    项目经理:“谢谢你们的肯定。”
    客户:   “不过打印的功能我想下个版本应该做好了吧?”
    项目经理:“你们的打印是不是要支持屏幕打印和纸张打印两种模式?”
    客户:    “Very Good!我就想这样做,你刚才不提醒我,我可能还忘了呢。”
    项目经理:“好的,下个版本我们会实现这个功能的。”
        等客户走后,项目经理的脸沉了下来:“狡猾狡猾的,先表扬了一下,我看就没有好心肠,这不,活又来了。”然后径直向程序员走去。

       
    客户就是上帝,这点我们不容怀疑。
        最苦的还是程序员,这点我们也不容怀疑。
        先来分析一下,这里有两种打印方式:POS机屏幕打印,纸张打印,理所当然要建一个抽象类,然后建两个子类。
        为了方便,我们这里只打印累计点数和金额。

       
        在main函数中加入以下代码:

        CPrint *pPrint =  new CScreenPrint;
        
    bool bRel = pPrint->Print(pMember->GetPoint(),fConsumeSum);
        assert(bRel);

        delete pPrint;
        pPrint 
    = new CPaperPrint;
        bRel 
    = pPrint->Print(pMember->GetPoint(),fConsumeSum);
        assert(bRel);
        delete pPrint;

        CPrint类代码如下:

    class CPrint  
    {
    public:
        
    virtual ~CPrint();
        
    virtual bool Print(int nPoint,float fSum) = 0;
    }
    ;

        CScreenPrint类代码如下:

    class CScreenPrint : public CPrint  
    {
    public:
        CScreenPrint();
        
    ~CScreenPrint();
         
    bool Print(int nPoint,float fSum);
    }
    ;

    bool CScreenPrint::Print(int nPoint,float fSum)
    {
        printf(
    "***Print on Screen:Point = %d, ConsumeSum =%f***\n",nPoint,fSum);
        
    return TRUE;
    }


        CPaperPrint类代码如下:

    class CPaperPrint : public CPrint  
    {
    public:
        CPaperPrint();
        
    ~CPaperPrint();
        
    bool Print(int nPoint,float fSum);
    }


    bool CPaperPrint::Print(int nPoint,float fSum)
    {
        printf(
    "$$$Print on Paper:Point = %d, ConsumeSum =%f$$$\n",nPoint,fSum);
        
    return TRUE;
    }


        编译通过,测试用例通过。
        程序运行的很好,没有新的需求,我们就让它这样吧,何必自寻烦恼呢?
        然而天下哪有这么好的事呢,过不了多久,客户就开始抱怨了:“我有两个分店,我想每个分店的打印格式不同。”
        不可否认,这确实是一个合理的要求,那就做吧,开始重构,使新功能更容易加入。
        首先进行改名,UML图如下:

       

        修改CScreenPrintShop1::Print函数为:

    bool CScreenPrintShop1::Print(int nPoint,float fSum)
    {
        printf(
    "***Shop 1 Print on Screen:Point = %d, ConsumeSum =%f***\n",nPoint,fSum);
        
    return TRUE;
    }

    修改CPaperPrintShop1::Print函数为:

    bool CPaperPrintShop1::Print(int nPoint,float fSum)
    {
        printf(
    "$$$Shop 1 Print on Paper:Point = %d, ConsumeSum =%f$$$\n",nPoint,fSum);
        
    return TRUE;
    }

        当然main函数中也要做相应地改动。
        编译通过,测试用例通过。
        现在可以增加shop 2了,UML图如下:

        
        代码我就不再贴了,和shop1差不多。把出现调用CPaperPrintShop1、CScreenPrintShop1的地方都修改为Shop2,编译通过,测试用例通过。
        马上有朋友会问了,这不是一个很明确的Factory Method设计模式吗?是的,这是Factory Method设计模式的应用,但我们只有在一处调用,何必麻烦去写Factory类呢?毕竟使用一些模式会增加好多的代码。
        记住一点:不一定用上设计模式才是完美的,实用才是硬道理。
        但正如你所说,随着需求的变化,程序中有两处或两处以上用到了打印的功能,那我们就必须修改了。UML图如下:

       

        不慌写代码,这里我们还能分析一下,Screen Print和Paper Print都会用到,为何我们不合并一下呢?UML图如下:

       

        这是一个什么模式啊?其实这是Abstract Factory的简化版。
        现在在一开始就初始化打印:

        CPrintFactory*  pPrintFactory = new CShop1PrintFactory;

        然后在调用的地方写如下代码:

        CPrint *pPrint =  pPrintFactory->CreateScreenPrint();
        
    bool bRel = pPrint->Print(pMember->GetPoint(),fConsumeSum);
        assert(bRel);

        delete pPrint;
        pPrint 
    = pPrintFactory->CreatePaperPrint();
        bRel 
    = pPrint->Print(pMember->GetPoint(),fConsumeSum);
        assert(bRel);
        delete pPrint;

        开始写代码吧,用在写代码的时间其实是比较少的,大多数的时间都是在设计和调试上,而调试的时间又占了大部分,我们要增加编程的效率,缩短调试的时间是最有效的,而建立测试用例就是一个很有效的方法。
        使用C++语言编写,在VC++ 6.0环境调试通过。
        代码下载
    参考资料:
     Refactoring: Improving the Design of Existing Code》 ――Martin Fowler
     Design Patterns - Elements of Reusable Object-Oriented Software》 ――GoF

  • 相关阅读:
    编程语言学哪个比较好?
    C#一定要避免程序中很多的依靠
    EXPIREAT
    EXISTS
    DUMP
    Python之sys模块
    Python的OS模块
    CentOS 7上安装gitlab-runner
    PyCharm激活方法
    Linux03 文件的相关操作(touch、rm、mv、cat)
  • 原文地址:https://www.cnblogs.com/goodcandle/p/book3.html
Copyright © 2020-2023  润新知