工厂方法模式的定义
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种创建对象的接口,但由子类决定实例化的具体类是哪一个。这样,工厂方法模式将对象的实例化推迟到子类,从而实现了解耦。
工厂方法模式的结构
工厂方法模式主要包括以下几个部分:
- 产品接口 :定义了工厂方法所创建对象的接口。
- 具体产品 :实现了产品接口的具体类。
- 工厂接口 :声明了返回产品对象的工厂方法。该方法的返回类型是产品接口类型。
- 具体工厂 :实现了工厂接口的具体类,覆盖了工厂方法以创建具体产品实例。
工厂方法模式特点
-
定义一个抽象工厂接口,由子类实现具体的产品创建。
-
客户端通过抽象工厂接口来创建具体产品,而不需要知道具体实现。
-
适用于产品种类较多且经常需要增加新产品的场景。
优点
-
解耦:将对象的创建与使用分离,降低了代码的耦合性。
-
扩展性:可以通过添加新的具体工厂和具体产品来扩展系统,而无需修改现有代码。
缺点
-
代码复杂度增加:引入了更多的类和接口,使代码结构更加复杂。
-
可能导致过多的子类:每添加一种新的产品类型,都需要添加一个新的具体工厂类,可能会导致类爆炸。
工厂方法模式在需要将对象创建与对象使用解耦,并且有可能需要经常增加新产品的场景下非常有用。
代码示例
1、接口和基类
class ISale {
public:
virtual double acceptCash(double, int) = 0;
virtual ~ISale() {}
};
class CashSuper : public ISale {
public:
void decorate(ISale* component) {
m_component = component;
}
double acceptCash(double price, int num) override {
double result = 0;
if (m_component != nullptr) {
result = m_component->acceptCash(price, num);
}
return result;
}
protected:
ISale* m_component = nullptr;
};
-
ISale是一个抽象接口,定义了acceptCash方法。 -
CashSuper实现了ISale接口,并提供了decorate方法,用于将其他ISale对象包装起来。
2、具体收费策略
class CashNormal : public ISale {
public:
double acceptCash(double price, int num) override {
return price * num;
}
};
class CashRebate : public CashSuper {
public:
CashRebate(double rebate) {
m_rebate = rebate;
}
double acceptCash(double price, int num) override {
double result = price * num * m_rebate;
return CashSuper::acceptCash(result, 1);
}
private:
double m_rebate = 1;
};
class CashReturn : public CashSuper {
public:
CashReturn(double condition, double moneyReturn) {
m_condition = condition;
m_return = moneyReturn;
}
double acceptCash(double price, int num) override {
double result = price * num;
if (m_condition > 0 && result >= m_condition) {
result = result - int(result / m_condition) * m_return;
}
return CashSuper::acceptCash(result, 1);
}
private:
double m_condition = 0;
double m_return = 0;
};
-
CashNormal:实现了正常收费策略。 -
CashRebate:实现了打折收费策略。 -
CashReturn:实现了满减收费策略。
3、工厂类
class IFactory {
public:
virtual ISale* createSaleModel() = 0;
};
class CashRebateReturnFactory : public IFactory {
public:
CashRebateReturnFactory(double rebate, double condition, double mReturn) {
m_rebate = rebate;
m_condition = condition;
m_return = mReturn;
}
ISale* createSaleModel() override {
CashNormal* cn = new CashNormal();
CashReturn* cr1 = new CashReturn(m_condition, m_return);
CashRebate* cr2 = new CashRebate(m_rebate);
cr1->decorate(cn);
cr2->decorate(cr1);
return cr2;
}
private:
double m_rebate = 1;
double m_condition = 0;
double m_return = 0;
};
class CashReturnRebateFactory : public IFactory {
public:
CashReturnRebateFactory(double rebate, double condition, double mReturn) {
m_rebate = rebate;
m_condition = condition;
m_return = mReturn;
}
ISale* createSaleModel() override {
CashNormal* cn = new CashNormal();
CashRebate* cr1 = new CashRebate(m_rebate);
CashReturn* cr2 = new CashReturn(m_condition, m_return);
cr1->decorate(cn);
cr2->decorate(cr1);
return cr2;
}
private:
double m_rebate = 1;
double m_condition = 0;
double m_return = 0;
};
-
IFactory:工厂接口,定义了createSaleModel方法。 -
CashRebateReturnFactory和CashReturnRebateFactory:具体工厂类,实现了先打折后满减和先满减后打折的策略组合。
4、客户端代码
class CashContext {
public:
CashContext(int type) {
IFactory* fs = nullptr;
switch (type) {
case 1:
fs = new CashReturnRebateFactory(1, 0, 0);
break;
case 2:
fs = new CashReturnRebateFactory(0.8, 0, 0);
break;
case 3:
fs = new CashReturnRebateFactory(0.7, 0, 0);
break;
case 4:
fs = new CashReturnRebateFactory(1, 300, 100);
break;
case 5:
fs = new CashRebateReturnFactory(0.8, 300, 100);
break;
case 6:
fs = new CashReturnRebateFactory(0.7, 200, 50);
break;
}
cs = fs->createSaleModel();
}
double getResult(double price, int num) {
return cs->acceptCash(price, num);
}
private:
ISale* cs;
};
int main() {
CashContext* cc1 = new CashContext(1);
CashContext* cc2 = new CashContext(2);
CashContext* cc3 = new CashContext(3);
CashContext* cc4 = new CashContext(4);
CashContext* cc5 = new CashContext(5);
CashContext* cc6 = new CashContext(6);
double result1 = cc1->getResult(84.8, 35);
double result2 = cc2->getResult(84.8, 35);
double result3 = cc3->getResult(84.8, 35);
double result4 = cc4->getResult(84.8, 35);
double result5 = cc5->getResult(84.8, 35);
double result6 = cc6->getResult(84.8, 35);
std::cout << "原价:" << result1 << std::endl;
std::cout << "打8折:" << result2 << std::endl;
std::cout << "打7折:" << result3 << std::endl;
std::cout << "满300返100:" << result4 << std::endl;
std::cout << "先打8折, 再满300减100:" << result5 << std::endl;
std::cout << "先满200减50,再打7折:" << result6 << std::endl;
delete cc1;
delete cc2;
delete cc3;
delete cc4;
delete cc5;
delete cc6;
return 0;
}
CashContext类:根据不同的type创建不同的具体工厂对象,通过工厂对象创建相应的ISale对象,并调用其acceptCash方法获取结果。
5、总结
这段代码通过装饰模式动态地组合不同的收费策略,并通过工厂方法模式实现不同收费策略的创建。这样设计使得系统更加灵活,易于扩展和维护。