第二章 商品促销-策略模式(读书笔记)
1.面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。
2.打一折和九折只是形式的不同,抽象分析出来,所有的打折算法都是一样的。所有每一种打折建一个类是非常不合适的。
3.简单工厂模式只是解决对象的创建问题,如果在商品促销系统中,经常性地改打折额度和返利额度,每次维护或扩展收费方式都要改动这个工厂。所有在这个商品促销的系统中简单工厂模式并不是很适用。
4.策略模式(Strategy):它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
5.算法本身只是一种策略,最重要的是算法如果是随时都可能互相替换的,这就是变化点。
6.简单工厂模式需要让客户端认识两个类,CashSuper和CashFactory,而策略模式与简单工厂结合的用法,客户端就只需要认识一个类CashContext就可以了,耦合更加降低了。(参照2.6)
7.策略模式的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
8.策略模式中的Context中封装了变化。选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。这样就最大化地减轻了客户端的职责。
9.策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
---------------------------------------------------------------------------------------------------------------------------------------
2.1商场收银软件的MFC版,先看看简单的界面
程序2.1 最简单的功能就在这两个按钮里面
void CDesignPartern21Dlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
UINT valA = GetDlgItemInt(IDC_EDIT1, NULL, FALSE);
UINT valB = GetDlgItemInt(IDC_EDIT2, NULL, FALSE);
SetDlgItemInt(IDC_EDIT3,valA * valB,FALSE);
//OnOK();
}
void CDesignPartern21Dlg::OnBnClickedCancel()
{
// TODO: 在此添加控件通知处理程序代码
SetDlgItemInt(IDC_EDIT1 ,0,FALSE);
SetDlgItemInt(IDC_EDIT2 ,0,FALSE);
SetDlgItemInt(IDC_EDIT3 ,0,FALSE);
//OnCancel();
}
---------------------------------------------------------------------------------------------------------------------------------------
程序2.3 商品促销软件的简单工厂实现
2.3.1 首先是现金类CashSuper.h
#pragma once
class CashSuper
{
public:
virtual double AcceptCash(double money) = 0;
};
class CashNormal :public CashSuper
{
public:
//正常收费,按原价返回
double AcceptCash(double money)
{
return money;
};
};
class CashRebate :public CashSuper
{
public:
CashRebate(double rebate)
:m_moneyRebate(1.0)
{
m_moneyRebate = rebate;
}
//打折后返回
double AcceptCash(double money)
{
return money * m_moneyRebate;
};
private:
double m_moneyRebate;
};
class CashReturn :public CashSuper
{
public:
CashReturn(double returnMoney,double condition)
:m_moneyReturn(0.0)
,m_moneyCondition(0.0)
{
m_moneyReturn = returnMoney;
m_moneyCondition = condition;
}
double AcceptCash(double money)
{
double resultMoney = money;
if (money > m_moneyCondition)
{//减去返利值
resultMoney = money - (money / m_moneyCondition )* m_moneyReturn;
}
return resultMoney;
};
private:
//返回现金
double m_moneyReturn;
//返利条件
double m_moneyCondition;
};
2.3.2 简单工厂类
#pragma once
#include "CashSuper.h"
typedef enum _Type
{
eNormal = 0,//正常收费
e80Discount,
e70Discount,
e50Discount,
eReturn //满300减100
}MyDiscount;
class CashFactory
{
public:
static CashSuper* CreateCashAccept(MyDiscount type)
{
CashSuper* cs = NULL;
switch (type)
{
case eNormal:
cs = new CashNormal();
break;
case e80Discount:
cs = new CashRebate(0.8);
break;
case e70Discount:
cs = new CashRebate(0.7);
break;
case e50Discount:
cs = new CashRebate(0.5);
break;
case eReturn:
cs = new CashReturn(100,300);
break;
default:
cs = new CashNormal();
break;
}
return cs;
};
};
2.3.3 客户端的调用
#include "stdafx.h"
#include "CashFactory.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
double Price;
double Num;
int selectedIndex;
//Price
cout << "please Input you Price: " << endl;
cin >> Price;
//Num
cout << "please Input you Num: " << endl;
cin >> Num;
//Discount
cout << "please Input you Discount: "
<< "0:正常收费, 1:8折, 2:7折, 3:5折, 4:满300减100" << endl;
cin >> selectedIndex;
CashSuper* cash = CashFactory::CreateCashAccept((MyDiscount)selectedIndex);
cout << "The total Price is "<< cash->AcceptCash(Price * Num) << endl;
return 0;
}
2.3.4 最后实现的UML就是和下面这个图一样
---------------------------------------------------------------------------------------------------------------------------------------
2.4 在我们用策略模式之前,先看看策略模式的图,比较一下就知道它和简单工厂模式的不同了。
-----------------------------------------------------------------------------------------------------------------------------------------------------------
2.5 看看这个商品促销系统是如何用上这个模式的。首先是图。
2.5.1 上面的图的代码实现,首先是现金类CashSuper.h
#pragma once
class CashSuper
{
public:
virtual double AcceptCash(double money) = 0;
};
class CashNormal :public CashSuper
{
public:
//正常收费,按原价返回
double AcceptCash(double money)
{
return money;
};
};
class CashRebate :public CashSuper
{
public:
CashRebate(double rebate)
:m_moneyRebate(1.0)
{
m_moneyRebate = rebate;
}
//打折后返回
double AcceptCash(double money)
{
return money * m_moneyRebate;
};
private:
double m_moneyRebate;
};
class CashReturn :public CashSuper
{
public:
CashReturn(double returnMoney,double condition)
:m_moneyReturn(0.0)
,m_moneyCondition(0.0)
{
m_moneyReturn = returnMoney;
m_moneyCondition = condition;
}
double AcceptCash(double money)
{
double resultMoney = money;
if (money > m_moneyCondition)
{//减去返利值
resultMoney = money - (money / m_moneyCondition )* m_moneyReturn;
}
return resultMoney;
};
private:
//返回现金
double m_moneyReturn;
//返利条件
double m_moneyCondition;
};
2.5.2 Context类的实现
#pragma once
#include "CashSuper.h"
class Context
{
public:
void SetContext(CashSuper* cashsuper)
{
m_pCashSuper = cashsuper;
};
double GetResult(double money)
{
return m_pCashSuper->AcceptCash(money);
};
~Context()
{
if (m_pCashSuper != NULL)
{
delete m_pCashSuper;
m_pCashSuper = NULL;
}
};
private:
CashSuper* m_pCashSuper;
};
2.5.3 客户端的调用方法
#include "stdafx.h"
#include <iostream>
#include "Context.h"
typedef enum _Type
{
eNormal = 0,//正常收费
e80Discount,
e70Discount,
e50Discount,
eReturn //满300减100
}MyDiscount;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
double Price;
double Num;
int selectedIndex;
//Price
cout << "please Input you Price: " << endl;
cin >> Price;
//Num
cout << "please Input you Num: " << endl;
cin >> Num;
//Discount
cout << "please Input you Discount: "
<< "0:正常收费, 1:8折, 2:7折, 3:5折, 4:满300减100" << endl;
cin >> selectedIndex;
Context context;
switch (selectedIndex)
{
case eNormal:
context.SetContext( new CashNormal());
break;
case e80Discount:
context.SetContext( new CashRebate(0.8));
break;
case e70Discount:
context.SetContext( new CashRebate(0.7));
break;
case e50Discount:
context.SetContext( new CashRebate(0.5));
break;
case eReturn:
context.SetContext( new CashReturn(100, 300));
break;
default:
context.SetContext( new CashNormal());
break;
}
cout << "The total Price is "<< context.GetResult(Num * Price) << endl;
return 0;
}
---------------------------------------------------------------------------------------------------------------------------------------
2.6 策略模式与简单工厂模式的结合,代码的耦合性进一步降低了。
2.6.1 首先是CashSuper.h,在这里基本没有什么改变
#pragma once
class CashSuper
{
public:
virtual double AcceptCash(double money) = 0;
};
class CashNormal :public CashSuper
{
public:
//正常收费,按原价返回
double AcceptCash(double money)
{
return money;
};
};
class CashRebate :public CashSuper
{
public:
CashRebate(double rebate)
:m_moneyRebate(1.0)
{
m_moneyRebate = rebate;
}
//打折后返回
double AcceptCash(double money)
{
return money * m_moneyRebate;
};
private:
double m_moneyRebate;
};
class CashReturn :public CashSuper
{
public:
CashReturn(double returnMoney,double condition)
:m_moneyReturn(0.0)
,m_moneyCondition(0.0)
{
m_moneyReturn = returnMoney;
m_moneyCondition = condition;
}
double AcceptCash(double money)
{
double resultMoney = money;
if (money > m_moneyCondition)
{//减去返利值
resultMoney = money - (money / m_moneyCondition )* m_moneyReturn;
}
return resultMoney;
};
private:
//返回现金
double m_moneyReturn;
//返利条件
double m_moneyCondition;
};
2.6.2 接下来是CashContext.h,简单工厂就在这里应用。
#pragma once
#include "CashSuper.h"
typedef enum _Type
{
eNormal = 0,//正常收费
e80Discount,
e70Discount,
e50Discount,
eReturn //满300减100
}MyDiscount;
class CashContext
{
public:
CashContext(MyDiscount discount)
:m_pCashSuper(NULL)
{
switch (discount)
{
case eNormal:
m_pCashSuper = new CashNormal();
break;
case e80Discount:
m_pCashSuper = new CashRebate(0.8);
break;
case e70Discount:
m_pCashSuper = new CashRebate(0.7);
break;
case e50Discount:
m_pCashSuper = new CashRebate(0.5);
break;
case eReturn:
m_pCashSuper = new CashReturn(100, 300);
break;
default:
m_pCashSuper = new CashNormal();
break;
}
};
double GetResult(double money)
{
return m_pCashSuper->AcceptCash(money);
};
~CashContext()
{
if (m_pCashSuper != NULL)
{
delete m_pCashSuper;
m_pCashSuper = NULL;
}
};
private:
CashSuper* m_pCashSuper;
};
2.6.3 客户端代码
#include "stdafx.h"
#include <iostream>
#include "CashContext.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
double Price;
double Num;
int selectedIndex;
//Price
cout << "please Input you Price: " << endl;
cin >> Price;
//Num
cout << "please Input you Num: " << endl;
cin >> Num;
//Discount
cout << "please Input you Discount: "
<< "0:正常收费, 1:8折, 2:7折, 3:5折, 4:满300减100" << endl;
cin >> selectedIndex;
CashContext cash((MyDiscount)selectedIndex);
cout << "The total Price is "<< cash.GetResult(Price * Num) << endl;
return 0;
}