设计模式---工厂方法模式

95 阅读4分钟

工厂方法模式的定义

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种创建对象的接口,但由子类决定实例化的具体类是哪一个。这样,工厂方法模式将对象的实例化推迟到子类,从而实现了解耦。

工厂方法模式的结构

工厂方法模式主要包括以下几个部分:

  1. 产品接口 :定义了工厂方法所创建对象的接口。
  2. 具体产品 :实现了产品接口的具体类。
  3. 工厂接口 :声明了返回产品对象的工厂方法。该方法的返回类型是产品接口类型。
  4. 具体工厂 :实现了工厂接口的具体类,覆盖了工厂方法以创建具体产品实例。

工厂方法模式特点

  • 定义一个抽象工厂接口,由子类实现具体的产品创建。

  • 客户端通过抽象工厂接口来创建具体产品,而不需要知道具体实现。

  • 适用于产品种类较多且经常需要增加新产品的场景。

优点

  • 解耦:将对象的创建与使用分离,降低了代码的耦合性。

  • 扩展性:可以通过添加新的具体工厂和具体产品来扩展系统,而无需修改现有代码。

缺点

  • 代码复杂度增加:引入了更多的类和接口,使代码结构更加复杂。

  • 可能导致过多的子类:每添加一种新的产品类型,都需要添加一个新的具体工厂类,可能会导致类爆炸。

工厂方法模式在需要将对象创建与对象使用解耦,并且有可能需要经常增加新产品的场景下非常有用。

代码示例

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 方法。

  • CashRebateReturnFactoryCashReturnRebateFactory:具体工厂类,实现了先打折后满减和先满减后打折的策略组合。

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、总结

这段代码通过装饰模式动态地组合不同的收费策略,并通过工厂方法模式实现不同收费策略的创建。这样设计使得系统更加灵活,易于扩展和维护。