zoukankan      html  css  js  c++  java
  • 书店会员销售系统(一)

    书店会员销售系统(一)
                         ――OORefactoring and Design Pattern
    本节目的:
       
    1.         有一场景引入一个问题,学习测试驱动的编程方法,实现基本功能。
    书店中的一幕:
          营业员:“请问你有会员卡吗?”
           顾客: “有的。”
           顾客掏出钱包,拿出会员卡递给营业员,营业员输入会员卡号后开始计书的金额,期间有一本书的条形码扫描不出来,营业员手动输入。
           营业员:“一共是126元。”
           顾客递给营业员130元。
           营业员:“收你130元,找你3元。”
        顾客: “你算错了吧?”
        营业员:“噢,不好意思,再给你1元。”(肯定在想哪件漂亮的衣服)
           顾客:  “我想问一下,我会员卡上的积分是多少了?”
           营业员: “你总共消费累计2700元,积分为250点。”
          顾客:    “那我现在享受几折优惠了?”
           营业员: “你现在可以享受8.5折优惠。”
           顾客:      “噢,我知道了,谢谢你。”
     
        顾客提着书离开收银台。
            我想这一场景大家可能都亲身经历过,当然不一定在书店。这就涉及到小店会员销售系统,如果要你编写这么一个系统,你会如何做呢?
           我想你第一个想到的可能是数据库。是的,会员销售系统会记录很多的信息,肯定是要用到数据库的,但后面的叙述我会尽可能地去避免,为了简单而已。
           我们先来分析一下问题。在上面的场景中涉及到一些对象:顾客、营业员、会员卡、书。顾客有顾客的信息,营业员有营业员的信息,会员卡记录了顾客的ID号,书的价格,在这里我先忽略书的价格,而是计算一次消费的金额,饭要一口一口地吃,还有营业员我们也可以先不涉及。

        我们要实现的功能是:根据不同的会员,对其消费的金额进行打折,并累计消费点数,第一版UML图如下:

         
         
    XP
    的原则是先写测试用例,然后使测试用例通过调试,得出正确的结果,我在这里也就按部就班的这么做。

    int main(int argc, char* argv[])
    {
           
    char szMemberID[MAX_PATH];
           strcpy(szMemberID,
    "00000001");
           
    float fConsumeSum = 120.0;
           
    int      nPoint  = 0;

            CCalculate      
    *pCalc = new CCalculate();
           CMember              
    *pMember = new CMember(szMemberID,1000.0,75);
           nPoint 
    = pMember->GetPoint();
           nPoint 
    += pCalc->CalculatePoint(fConsumeSum);

            fConsumeSum 
    = pCalc->CalcMoney(fConsumeSum,pMember);

            pMember
    ->SetPoint(nPoint);
            assert(nPoint 
    == 87);
            assert(fConsumeSum 
    == 120.0);

            printf(
    "Point = %d\n",nPoint);
            printf(
    "ConsumeSum = %f\n",fConsumeSum);
            delete pCalc;
            delete pMember;
            
    return 0;
    }



           因为篇幅的原因,所有出错处理都不考虑。
           编译一下,很多错误,主要是CCalculateCMember三个类没有创建,那接下来的工作当然是创建它们。
     
     会员类:

    class CMember  
    {
    public:
        CMember(
    char *pszID,float fSum,int nPoint);
        
    ~CMember();
        
    int GetPoint();
        
    void SetPoint(int nPoint);
        
    float GetRebate();
    private:
        
    char    m_szID[MAX_PATH];
        
    float   m_fSum;
        
    int     m_nPoint;
    }
    ;
     
    CMember::CMember(
    char *pszID,float fSum,int nPoint)
    {
        
    if(pszID)
            strcpy(m_szID,pszID);
        m_fSum 
    = fSum;
        m_nPoint 
    = nPoint;
    }

     
    int CMember::GetPoint()
    {
        
    return m_nPoint;
    }

     
    void CMember::SetPoint(int nPoint)
    {
        m_nPoint 
    = nPoint;
    }

     
    float CMember::GetRebate()
    {
        
    if(m_nPoint<=100)
            
    return 10;
        
    else if(m_nPoint>100 && m_nPoint <200)
            
    return 9.5;
        
    else if(m_nPoint>=200 && m_nPoint <400)
            
    return 9;
        
    else if(m_nPoint>=400 && m_nPoint <600)
            
    return 8.5;
        
    else
            
    return 8.0;
    }



    计算类:

    class CCalculate  
    {
    public:
        CCalculate();
        
    ~CCalculate();
        
    int CalculatePoint(float fSum);
        
    float CalcMoney(float fSum,CMember  *pMember);
    }
    ;

    int CCalculate::CalculatePoint(float fSum)
    {
        
    int nPoint = (int)(fSum/10);
        
    return nPoint;
    }

     
    float CCalculate::CalcMoney(float fSum,CMember  *pMember)
    {
        
    float fRebateSum = 0.0;
        fRebateSum 
    = fSum * pMember->GetRebate();
        
    return fRebateSum;
    }


        然后在编译程序,在测试用例中,我们希望的结果是:
        Point = 87
        ConsumeSum = 120.000000
        可运行的结果却是出现assert异常,仔细一查,输出结果为:
        Point = 87
        ConsumeSum = 1200.000000

        原来在折扣上没有除10,修改代码:

    float CCalculate::CalcMoney(float fSum,CMember  *pMember)
    {
        
    float fRebateSum = 0.0;
        fRebateSum 
    = fSum * pMember->GetRebate()/10;
        
    return fRebateSum;
    }


        测试通过,一个基本功能的程序就编写成功了。当然一组测试用例远远是不够的,我这里也就不多写了。人还是人,错误是很难避免的,通过测试用例,能排除一大部分的问题,也为以后的程序改进提供的保障。
        也许会有人说,这样的设计太烂了。可如果需求不改变的话,至此就已经足够了。这不是本节的用意。

    参考资料:
    Refactoring: Improving the Design of Existing Code》 ――Martin Fowler

  • 相关阅读:
    webpack + vue 打包生成公共配置文件(域名) 方便动态修改
    前端实用工具大集合
    Javascript高级程序设计--读书笔记之理解原型对象
    Javascript高级程序设计--读书笔记之面向对象(二)
    Javascript高级程序设计--读书笔记之面向对象(一)
    Javascript高级程序设计--读书笔记之Array类型
    javascript 中的函数
    CF1037H Security (SAM+二维偏序)
    搜索和组合数学P1246 编码
    模拟画图题P1185 绘制二叉树
  • 原文地址:https://www.cnblogs.com/goodcandle/p/346471.html
Copyright © 2011-2022 走看看