【重走编程路】设计模式概述(二) -- 工厂方法模式、抽象工厂模式


前言

创建型模式主要关注对象的创建过程,提供了一种创建对象的最佳方式,并隐藏了创建逻辑的细节。本章介绍创建型模式中的工厂方法模式抽象工厂模式


设计模式详解

1. 简单工厂模式

又称静态工厂模式,包含一个抽象产品类,多个产品的实现类,一个工厂类。由工厂类的对象决定创建哪一种产品类的实例。

#include <iostream>
#include <string>
#include <memory>
using namespace std;

// 抽象产品类(所有产品的基类)
class Vehicle {
public:
	Vehicle() {}
	virtual void Wheel() = 0;
};

// 具体产品类
class Car : public Vehicle {
public:
	Car() {}
	virtual void Wheel() override {
		std::cout << "4个轮子" << std::endl;
	}
};
class Motorcycle : public Vehicle {
public:
	Motorcycle() {}
	virtual void Wheel() override {
		std::cout << "2个轮子" << std::endl;
	}
};

// 工厂类
class Factory {
public:
	static std::shared_ptr<Vehicle> Create(const std::string& name) {
		if (name == "小汽车") {
			return std::make_shared<Car>();
		}
		else if (name == "摩托车") {
			return std::make_shared<Motorcycle>();
		}
		else {
			std::cout << "没有这种产品" << std::endl;
			return nullptr;
		}
	}
};

int main() {
	std::shared_ptr<Vehicle> vehicle = Factory::Create("小汽车");
	vehicle->Wheel();
	vehicle = Factory::Create("摩托车");
	vehicle->Wheel();
	return 0;
}

优缺点

优点:
只需要传入一个正确的参数,就可以获取你所需要的对象,而无需知道其细节创建。
缺点:
工厂类的职责相对过重,增加新的产品,需要修改工厂类的判断逻辑,违背了开闭原则。

2. 工厂方法模式(Factory Method)

问题

在软件设计中,我们经常遇到需要创建不同类型对象的情况。但是,如果直接在代码中实例化对象,会使代码紧密耦合在一起,难以维护和扩展。此外,如果对象的创建方式需要变化,那么就需要在整个代码中进行大量的修改。工厂方法模式旨在解决这个问题。

解决方案

工厂方法模式又称多态性工厂模式。该模式定义了一个创建对象的接口,但是由子类决定要实例化的类是哪一个,也就是说相比简单工厂模式,工厂方法模式将实例化推迟到了子类中,核心的工厂类不再负责所有产品的创建,而是将具体的工作交给子类去做。

#include <iostream>
#include <string>
#include <memory>
using namespace std;

// 抽象产品类(所有产品的基类)
class Vehicle {
public:
    Vehicle() {}
    virtual void Wheel() = 0;
};

// 具体产品类
class Car : public Vehicle {
public:
    Car() {}
    virtual void Wheel() override {
        std::cout << "4个轮子" << std::endl;
    }
};
class Motorcycle : public Vehicle {
public:
    Motorcycle() {}
    virtual void Wheel() override {
        std::cout << "2个轮子" << std::endl;
    }
};

// 工厂类(抽象工厂)
class Factory {
public:
    virtual std::shared_ptr<Vehicle> Create() = 0;
};

//工厂类(具体工厂)
class CarFactory : public Factory {
public:
    virtual std::shared_ptr<Vehicle> Create() override {
        return std::make_shared<Car>();
    }
};
class MotorcycleFactory : public Factory {
public:
    virtual std::shared_ptr<Vehicle> Create() override {
        return std::make_shared<Motorcycle>();
    }
};

int main() {
    std::shared_ptr<Factory> factory(new CarFactory());
    std::shared_ptr<Vehicle> vehicle = factory->Create();
    vehicle->Wheel();
    factory.reset(new MotorcycleFactory());
    vehicle = factory->Create();
    vehicle->Wheel();
    return 0;
}

优缺点

优点:
用户只需要关心所需产品对应的工厂,无需关心创建细节;加入新产品时符合开闭原则,不需要修改其他的工厂类的代码,提高了可扩展性。
缺点:
类的个数容易过多(每个工厂只负责生产一种产品),增加了复杂度;增加了系统的抽象性和理解难度。

3. 抽象工厂模式

问题

在某些情况下,需要创建一系列相关或相互依赖的对象,这些对象属于一组相关的产品族。同时,系统需要保证这些产品族之间的一致性。如果直接在代码中创建这些对象,会使得代码与具体产品的细节紧密耦合,不利于后续的扩展和维护。

解决方案

抽象工厂模式提供了一个接口,用于创建一系列相关或相互依赖的对象。通过使用抽象工厂接口及其具体实现,可以将对象的创建与客户端代码分离,从而实现系统的松耦合。与工厂方法模式不同的是,工厂方法模式中的工厂只生产单一的产品,而抽象工厂模式中的工厂生产多个产品。

抽象工厂模式涉及多个角色
  • 抽象工厂(Abstract Factory):声明了一组用于创建不同产品的抽象方法。具体的工厂类必须实现这些方法来创建具体的产品对象。
  • 具体工厂(Concrete Factory):实现抽象工厂接口,负责创建特定种类的产品对象。
  • 抽象产品(Abstract Product):定义了产品的通用接口,具体产品必须实现这个接口。
  • 具体产品(Concrete Product):实现抽象产品接口,是抽象工厂创建的实际对象。
#include <iostream>
#include <string>
#include <memory>
using namespace std;

// 系列产品1
class Vehicle {
public:
    Vehicle(string name) : m_name(name) {}
    virtual void Show() = 0;
protected :
    string m_name;
};
class Car : public Vehicle {
public:
    Car(string name) : Vehicle(name) {}
    void Show() override {
        cout << "生产了一辆小汽车: " << m_name << endl;
    }
};
class Motorcycle :public Vehicle {
public:
    Motorcycle(string name) : Vehicle(name) {}
    void Show() override {
        cout << "生产了一辆摩托车: " << m_name << endl;
    }
};

// 系列产品2
class Light {
public:
    Light() {}
    virtual void Show() = 0;
};
class CarLight :public Light {
public:
    void Show() override {
        cout << "小汽车灯!" << endl;
    }
};
class MotorcycleLight :public Light {
public:
    void Show() override {
        cout << "摩托车灯!" << endl;
    }
};

// 工厂方法  => 抽象工厂(对有一组关联关系的产品簇提供产品对象的统一创建)
class AbstractFactory {
public:
    virtual shared_ptr<Vehicle> createVehicle(string name) = 0; // 工厂方法  创建机动车
    virtual shared_ptr<Light> createLight() = 0;             // 工厂方法     创建水果
};
// 宝马工厂
class BMWFactory :public AbstractFactory {
public:
    shared_ptr<Vehicle> createVehicle(string name) override {
        return make_shared<Car>(name);
    }
    shared_ptr<Light> createLight() override {
        return make_shared<CarLight>();
    }
};
// 哈雷工厂
class HarleyFactory :public AbstractFactory {
public:
    shared_ptr<Vehicle> createVehicle(string name) override {
        return make_shared<Motorcycle>(name);
    }
    shared_ptr<Light> createLight() override {
        return make_shared<MotorcycleLight>();
    }
};

int main() {
    shared_ptr<AbstractFactory> bmwFac (new BMWFactory());
    shared_ptr<Vehicle> vehicle = bmwFac->createVehicle("汗血宝马");
    vehicle->Show();
    shared_ptr<Light> light = bmwFac->createLight();
    light->Show();

    shared_ptr<AbstractFactory> harleyFac(new HarleyFactory());
    vehicle = harleyFac->createVehicle("地狱摩托");
    vehicle->Show();
    light = harleyFac->createLight();
    light->Show();
    return 0;
}
适用场景

抽象工厂模式最早的应用是用于创建属于不同操作系统的视窗构件。如 java 的 AWT 中的 Button 和 Text 等构件在 Windows 和 UNIX 中的本地实现是不同的。

  1. 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  2. 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  3. 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

抽象工厂模式的扩展有一定的“开闭原则”倾斜性:

  1. 当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
  2. 当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。
    另一方面,当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式。

优缺点

优点:

  • 抽象工厂封装了变化,封装了对象创建的具体细节
  • 增加新的产品族很方便,无须修改已有系统
  • 针对接口进行编程而不是针对具体进行编程

缺点:

  • 增加新的产品等级结构需对原系统做较大修改(违背开放封闭)

To be continued.

  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值