内容要求
在这边把两次作业合在一起。作业要求实现一个商场结算程序。其中要完成几个功能:
- 结算模块。针对不同的商品不同的营销策略(不同打折方式)进行结算;
- 商品状态。商品需要至少包含
在售
,缺货
以及上架中
等三种状态; - 商品上架审核功能。
针对这三个功能,我将程序拆开成三个部分看待:商品模块,结算模块,审核模块。
商品模块
设计商品基类。在这里我打算设计成单例模式。因此商品类别是独一份的,这样有个好处就是商品的价格一直是统一的,并不会因为新创建了新的对象而导致出现同一类商品出现不同价格的情况。
class Product {
public:
virtual double GetPrice() = 0;
virtual void SetPrice(double price) = 0;
virtual void SetState(State *state) = 0;
virtual bool isOnSale() = 0;
virtual ProductKey GetName() = 0;
virtual void ShowState() = 0;
};
基于基类,创建子类 Pen, Suit 以及 Book。以下只放出来 Pen 类。
class Pen : public Product {
private:
State *state_;
double price_;
ProductKey name_;
static Pen *instance_;
static std::mutex mutex;
Pen();
public:
static Pen *GetInstance();
double GetPrice();
void SetPrice(double price);
void SetState(State *state);
bool isOnSale();
ProductKey GetName();
void ShowState();
};
同时题目中有提到至少有三种状态,因此考虑到之后可能新增状态,这边把状态也当作一个类别,作为商品的一个属性。
class State {
public:
virtual void writeState(Product *p) = 0;
virtual bool isAvaible() = 0;
};
class onSale : public State {
public:
void writeState(Product *p) override;
bool isAvaible() override;
};
class outOfStock : public State {
public:
void writeState(Product *p) override;
bool isAvaible() override;
};
class waitting : public State {
public:
void writeState(Product *p) override;
bool isAvaible() override;
};
而为了将商品实现细节对外隐藏,这边尝试新建了 ProductList 类别,用来作为与外界的接口。这样之后新增商品就不需要动到其他模块。这边的应用应该算是策略模式吧。
class ProductList {
private:
std::map<std::string, ProductKey> list_ = {
{"Pen", PEN},
{"Suit",SUIT},
{"Book", BOOK},
};
public:
ProductList(){};
ProductKey GetProductKey(std::string p_name);
Product *GetInstance(std::string p_name);
double GetPrice(std::string p_name);
void SetPrice(std::string p_name, double price);
void SetState(std::string p_name, std::string state);
bool isOnSale(std::string p_name);
void ShowState(std::string);
};
结算模块
在结算模块中,本程序使用了策略方式模式。创建了三种营销方式,分别是普通(Normal),打折(Rebate)以及返利(Return)。
class StrategyBase {
public:
virtual double acceptCash(double money) const = 0;
};
class StrategyNormal : public StrategyBase {
public:
double acceptCash(double money) const override;
};
class StrategyRebate : public StrategyBase {
private:
double money_rebate_ = 1.0;
public:
explicit StrategyRebate(double money_rebate);
double acceptCash(double money) const override;
};
class StrategyReturn : public StrategyBase {
private:
double money_contion_ = 0.0;
double money_return_ = 0.0;
public:
explicit StrategyReturn(double money_contion, double money_return);
double acceptCash(double money) const override;
};
但此时还存在一个问题,就是每个商品的营销策略可能不同,我们当前还没维护商品的营销策略。在此我为了尽可能不修改已有的代码,对每个商品的营销策略进行了维护。
class ProduceStrategy {
private:
std::map<ProductKey, StrategyKey> mp = {
{PEN, moneyRebate_008},
{SUIT, moneyReturn_10_1},
{BOOK, moneyNormal},
};
static ProduceStrategy *instance_;
ProduceStrategy() = default;
public:
static ProduceStrategy *GetInstance();
StrategyKey GetStrategy(ProductKey pk);
void Update(ProductKey pk, StrategyKey sk);
};
这样当之后商品的营销策略发生改变之后,我们也能使用 ProduceStrategy 类进行维护更新。同时为了营销策略的唯一,这边使用了单例模式。
class CashAll {
private:
ProduceStrategy *ps_;
ProductList *pl_;
public:
CashAll(ProduceStrategy *ps, ProductList *pl);
double acceptCash(std::vector<std::string> prods);
};
之后根据策略以及商品属性,我们计算需要收的金额。
审核模块
在审核模块中,这边使用了职责链模式。需要设计请求类别以及管理者类别。
请求类别如下
class RequstStocking {
private:
Product *pd_;
public:
RequstStocking(Product *pd);
void SetProduct(Product *pd);
void finish();
};
设计进货上架审核要经过仓库中心(ProCenter),售卖中心(SaleCenter)以及总理(Manager)审核。这三类都继承于管理者(Manager)
class Manager {
protected:
Manager *superior_;
public:
Manager();
void SetSuperior(Manager *superior);
virtual void RequstApplications(RequstStocking *req) = 0;
};
class ProCenter : public Manager {
public:
ProCenter();
void RequstApplications(RequstStocking *req) override;
};
class SaleCenter : public Manager {
public:
SaleCenter();
void RequstApplications(RequstStocking *req) override;
};
class CommonManager : public Manager {
public:
CommonManager();
void RequstApplications(RequstStocking *req) override;
};
结果
为了更方便检测代码,这边将各个模块分开测试。
商品模块
int main() {
ProductList *list_p = new ProductList;
list_p->ShowState("Pen");
if (list_p->isOnSale("Pen"))
std::cout << "Pen is on sale" << std::endl;
list_p->SetState("Pen", "缺货");
list_p->ShowState("Pen");
if (list_p->isOnSale("Pen") == false)
std::cout << "Pen is not on sale" << std::endl;
std::cout << "Pen price : " << list_p->GetPrice("Pen") << std::endl;
return 0;
}
![[image-20221230175556952.png]]
结算模块
int main() {
std::vector<std::string> list_p;
list_p.push_back("Pen");
list_p.push_back("Book")
ProduceStrategy *ps = ProduceStrategy::GetInstance();
std::cout << ps->GetStrategy(PEN) << std::endl;
ProductList *pl = new ProductList;
CashAll *ca = new CashAll(ps, pl);
std::cout << ca->acceptCash(list_p) << std::endl;
return 0;
}
![[image-20221230180011043.png]]
这边的 Pen 原价 10,打8折;Book 原价 15.5,没参与活动。
审核模块
int main() {
Product *p = Pen::GetInstance();
RequstStocking *req = new RequstStocking(p);
p->ShowState();
ProCenter *pc = new ProCenter;
SaleCenter *sc = new SaleCenter;
CommonManager *cm = new CommonManager;
pc->SetSuperior(sc);
sc->SetSuperior(cm);
pc->RequstApplications(req);
p->ShowState();
return 0;
}
![[image-20221230180358924.png]]
PS:考虑到具体实现放上来会比较乱,同时最近比较忙,等整理完之后会将代码交互等地方整理好之后再上传。
在这次学习中,收获还是挺大的。由于本身是做 AI 方向的研究,对于代码的工程化能力较差。本次通过学习并且通过大作业将设计模式大体梳理了下,对于程序的结构有了更加清晰的认识。果然 talk is cheap, show me the code。