设计模式学习笔记——工厂模式

学习一下设计模式中的工厂模式,自娱自乐写点代码玩玩,顺便复习一下智能指针。由于本人才疏学浅,写的代码可能有问题,同时设计模式比较抽象,只能想办法打比方把它们换成自己熟悉的具体东西来理解,但打比方肯定不可能完全贴切。因此若有问题还请见谅。

前言

工厂模式可以由简单到抽象分为简单工厂模式工厂方法模式抽象工厂模式。这几种模式都属于创建型模式,这种模式将对象的创建与使用分离,用户在要使用某个对象时,只需要类向用户提供的创建对象的接口,就可以方便地创建想要的对象,之后便可以使用对象。在整个过程中用户可以不必关心具体的创建及实现细节。

下面对这几种模式进行学习。

简单工厂模式

简单工厂模式(Simple Factory Pattern),又称为静态工厂方法(Static Factory Method)模式。使用简单工厂模式,我们可以创建一个“工厂”,然后向这个工厂提出需求(向接口传递参数),工厂根据不同的需求返回不同的“产品”(类的实例)。

简单工厂模式包含以下角色:

  • 工厂角色:按照需求“生产”所需要的产品,即创建对应的对象,内含逻辑判断,由一个工厂类实现
  • 抽象产品角色:所有所创建的对象的父类,描述所有具体产品类的公共接口,由一个抽象产品类实现
  • 具体产品角色:所要创建的具体产品,所创建的对象都是这个角色的某个具体类的示例,由具体产品类实现

C++代码

#include<iostream>
using namespace std;

//产品种类标识
typedef enum ProductType {
	ProductA,//0
	ProductB,//1
}ProductType;

// 抽象产品类,用于实现抽象产品角色
class Product
{
public:
	virtual ~Product() { };
	virtual void use() = 0;//使用产品,抽象产品类不需要被使用,因此声明为纯虚函数,对应的类即为抽象类
};

// 具体产品类A,用于实现具体产品角色A
class ConcreteProductA : public Product {
public:
	virtual ~ConcreteProductA() {
		cout << "Product A has been destroyed" << endl;
	};

	void use() {
		cout << "I am product A" << endl;
	}
};

// 具体产品类B,用于实现具体产品角色B
class ConcreteProductB : public Product {
public:
	virtual ~ConcreteProductB() {
		cout << "Product B has been destroyed" << endl;
	};

	void use() {
		cout << "I am product B" << endl;
	}
};

// 工厂类,用于实现工厂角色
class Factory {
public:
	virtual ~Factory() { };	

	Product* CreateProduct(ProductType Type) {
		switch (Type) {
		case ProductA: return new ConcreteProductA();
		case ProductB: return new ConcreteProductB();
		}
	}
};

int main() {
	Factory* factory = new Factory();
	Product* product_a = factory->CreateProduct(ProductA);
	Product* product_b = factory->CreateProduct(ProductB);
	product_a->use();
	product_b->use();

	delete factory;
	delete product_a;
	delete product_b;
	return 0;
}

运行结果
在这里插入图片描述

等等,万一忘了delete岂不是内存泄露?换成智能指针玩一玩。

/*
同上
*/

// 工厂类,用于实现工厂角色
class Factory{
public:
	virtual ~Factory() { };	

	shared_ptr<Product> CreateProduct(ProductType Type){
		switch (Type){
		case ProductA: return make_shared<ConcreteProductA>();
		case ProductB: return make_shared<ConcreteProductB>();
		}
	}
};

int main(){
	shared_ptr<Factory> factory(new Factory);
	shared_ptr<Product> product_a = factory->CreateProduct(ProductA);
	shared_ptr<Product> product_b = factory->CreateProduct(ProductB);
	product_a->use();
	product_b->use();
	return 0;
}

运行结果
注意析构顺序
在这里插入图片描述

简单工厂模式特点

简单工厂模式实现了对象的创建及使用的分离。简单工厂模式能根据客户给出的参数创建对应的产品,客户只需要记住对应的产品参数,向工厂提供该参数即可返回需要的实例对象,并不需要了解对象是怎么创建的。这样一来免去了客户直接创建产品对象的麻烦。

然而简单工厂模式过于简单,可扩展性很差如果要添加新的产品就要修改工厂类,修改相应的逻辑判断分支,违反了开闭原则。如果产品种类很多,则工厂类将变得十分复杂。同时,简单工厂模型的产品生产都在一个工厂中,一旦不能正常工作,整个工程都要受到影响。

总之当产品种类比较少的时候,简单工厂模式有其用武之处。

注:开闭原则定义,摘自度娘

在面向对象编程领域中,开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。

工厂方法模式

工厂方法模式(Factory Method Pattern)不再使用一个工厂角色进行产品的生产,其将工厂也分为抽象工厂角色和具体工厂角色。具体的生产任务由抽象工厂角色派生出的具体工厂角色进行。打个比方就是工厂下面有两个生产车间生产不同产品。工厂方法模式在要添加新的产品时,不需要修改抽象工厂类,只需要添加一个具体工厂类。就好比引入多个生产车间生产不同产品,这样一来也分担了生产压力,某个车间出问题不至于整个工程停工。相比于简单工厂模式,工厂方法模式更符合开闭原则。

工厂方法模式包含如下角色:

  • 抽象工厂角色:具体工厂角色的父类,声明具体工厂角色必须实现的接口,可以由一个抽象类来实现
  • 具体工厂角色:负责具体的产品生产,由具体工厂类实现
  • 抽象产品角色:同简单工厂模式
  • 具体产品角色:同简单工厂模式

C++代码

#include<iostream>
using namespace std;

// 抽象产品类,用于实现抽象产品角色
class Product
{
public:
	virtual ~Product() { };
	virtual void use() = 0;//使用产品,抽象产品类不需要被使用,因此声明为纯虚函数,对应的类即为抽象类
};

// 具体产品类A,用于实现具体产品角色A
class ConcreteProductA : public Product {
public:
	virtual ~ConcreteProductA() {
		cout << "Product A has been destroyed" << endl;
	};

	void use() {
		cout << "I am product A" << endl;
	}
};


// 具体产品类B,用于实现具体产品角色B
class ConcreteProductB : public Product {
public:
	virtual ~ConcreteProductB() {
		cout << "Product B has been destroyed" << endl;
	};

	void use() {
		cout << "I am product B" << endl;
	}
};

//抽象工厂类,不直接用于生产具体产品,但要声明生产接口
class Factory
{
public:
	virtual ~Factory() { };

	//生产产品的接口
	//抽象工厂类不需要实现这个接口,也不需要抽象工厂对象
	//因此声明为纯虚函数,对应的类即为抽象类
	virtual shared_ptr<Product> CreateProduct() = 0;

};

//具体工厂A,用于生产产品A
class ConcreteFactoryA : public Factory{
public:
	virtual ~ConcreteFactoryA() { };

	shared_ptr<Product> CreateProduct(){
		return make_shared<ConcreteProductA>();
	}
};

//具体工厂B,用于生产产品B
class ConcreteFactoryB : public Factory {
public:
	virtual ~ConcreteFactoryB() { };

	shared_ptr<Product> CreateProduct() {
		return make_shared<ConcreteProductB>();
	}
};

int main() {
	shared_ptr<Factory> factoryA(new ConcreteFactoryA);
	shared_ptr<Factory> factoryB(new ConcreteFactoryB);
	shared_ptr<Product> product_a = factoryA->CreateProduct();
	shared_ptr<Product> product_b = factoryB->CreateProduct();
	product_a->use();
	product_b->use();
	return 0;
}

运行结果
在这里插入图片描述
工厂方法模式特点
工厂方法模式保留了简单工厂模式的优点,即隐藏了产品的生产过程,所不同之处在于客户要提供生产对应产品的工厂,而不是产品参数,不过客户依旧可以不关心具体的生产过程,直接使用对应工厂的创建接口创建对象进行使用。

相比于简单工厂模式,工厂方法模式在抽象工厂类中仅声明创建对象的接口,具体的创建细节封装在各个具体的工厂类中,这样一来,在添加新产品时,无需修改抽象工厂类、抽象产品类以及其他具体工厂类和具体产品类,仅需添加生产新产品的具体工厂类,以及新产品对应的具体产品类即可。可扩展性较好,更符合开闭原则。让各个具体工厂类进行生产也分担了生产压力,同时,在某个具体工厂出现问题时只会使得具体的产品生产受到影响,不会对其他产品的生产造成影响。

工厂方法模式的缺点在于,在添加新产品时,需要添加新的具体产品类和具体工厂类,系统中类的个数将成对增加,增加了系统的复杂度。

抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)比工厂方法模式更抽象,且更具一般性。工厂方法模式中具体工厂生产具体产品,一个具体工厂就生产一种具体产品,但有时我们希望一个工厂生产多种产品,即能够生产一个产品族

产品族的概念很难抽象,借鉴网上看到过的一个比喻,自己也想个有意思(可能不恰当)的比喻来进行辅助理解。比如现在这么多电子品牌,例如小米、华为、苹果,都做手机、平板、笔记本电脑等等,手机、平板、笔记本电脑等等产品就构成一个产品族。

另外,每个产品都有其等级结构,即产品的继承结构,比如单说手机就是一个抽象的产品,具体到某个品牌的手机,比如小米手机,就是具体的产品,抽象的手机作为基类能派生出具体的小米手机、华为手机、苹果手机等,这就构成一个等级结构。而每个工厂,当然用上面比喻就是品牌,都生产位于不同产品等级结构的一组产品,比如小米公司做小米手机,小米平板、小米笔记本电脑。

抽象工厂模式能够完成我们的需求,其具体工厂角色能够生产不同等级结构的产品。我们为每个属于不同等级结构的产品都定义一个抽象产品类,然后每个抽象产品类派生出具体产品类。

抽象工厂模式包含如下角色:

  • 抽象工厂角色: 具体工厂角色的父类,声明具体工厂角色必须实现的接口,可以由一个抽象类来实现
  • 具体工厂角色:负责生产产品族中的具体产品,由具体的类来实现
  • 抽象产品角色:定义不同产品等级结构的产品,可以由抽象类实现
  • 具体产品角色:具体实现处于每个等级中的产品,由具体产品类实现

我在网上看到比较好的图,可以用来描述抽象工厂模式的各种角色之间的关系,现在自己也学着画一个:
在这里插入图片描述

C++代码

#include<iostream>
using namespace std;

// 抽象产品类A,具体产品类A1,A2的基类
class ProductA
{
public:
	virtual ~ProductA() { };
	virtual void useA() = 0;//A产品的公共接口
};

// 抽象产品类B,具体产品类B1,B2的基类
class ProductB
{
public:
	virtual ~ProductB() { };
	virtual void useB() = 0;//B产品的公共接口
};

// 具体产品类A1,用于实现具体产品角色A1
class ConcreteProductA1 : public ProductA {
public:
	virtual ~ConcreteProductA1() {
		cout << "Product A1 has been destroyed" << endl;
	};

	void useA() {
		cout << "I am product A from Factory1" << endl;
	}
};

// 具体产品类A2,用于实现具体产品角色A2
class ConcreteProductA2 : public ProductA {
public:
	virtual ~ConcreteProductA2() {
		cout << "Product A2 has been destroyed" << endl;
	};

	void useA() {
		cout << "I am product A from Factory2" << endl;
	}
};

// 具体产品类B1,用于实现具体产品角色B1
class ConcreteProductB1 : public ProductB {
public:
	virtual ~ConcreteProductB1() {
		cout << "Product B1 has been destroyed" << endl;
	};

	void useB() {
		cout << "I am product B from Factory1" << endl;
	}
};

// 具体产品类B2,用于实现具体产品角色A2
class ConcreteProductB2 : public ProductB {
public:
	virtual ~ConcreteProductB2() {
		cout << "Product B2 has been destroyed" << endl;
	};

	void useB() {
		cout << "I am product B from Factory2" << endl;
	}
};

//抽象工厂类,不直接用于生产具体产品,但要声明生产接口
class Factory
{
public:
	virtual ~Factory() { };

	//生产产品的接口,每个具体工厂要生产多种不同等级结构的产品
	virtual shared_ptr<ProductA> CreateProductA() = 0;
	virtual shared_ptr<ProductB> CreateProductB() = 0;
};

//具体工厂1,用于生产产品A1和B1
class ConcreteFactory1 : public Factory{
public:
	virtual ~ConcreteFactory1() { };

	shared_ptr<ProductA> CreateProductA(){
		return make_shared<ConcreteProductA1>();
	}
	shared_ptr<ProductB> CreateProductB() {
		return make_shared<ConcreteProductB1>();
	}
};

//具体工厂2,用于生产产品A2和B2
class ConcreteFactory2 : public Factory {
public:
	virtual ~ConcreteFactory2() { };

	shared_ptr<ProductA> CreateProductA() {
		return make_shared<ConcreteProductA2>();
	}
	shared_ptr<ProductB> CreateProductB() {
		return make_shared<ConcreteProductB2>();
	}
};

int main() {
	//实例化两个具体工厂
	shared_ptr<Factory> factory1(new ConcreteFactory1);
	shared_ptr<Factory> factory2(new ConcreteFactory2);
	//具体工厂1的两种产品
	shared_ptr<ProductA> product_a1 = factory1->CreateProductA();
	shared_ptr<ProductB> product_b1 = factory1->CreateProductB();
	//具体工厂2的两种产品
	shared_ptr<ProductA> product_a2 = factory2->CreateProductA();
	shared_ptr<ProductB> product_b2 = factory2->CreateProductB();
	//使用产品
	product_a1->useA();
	product_b1->useB();
	product_a2->useA();
	product_b2->useB();
	return 0;
}

运行结果
在这里插入图片描述

抽象工厂模式特点
抽象工厂模式依旧有着分离对象的创建及使用的优势,用户无需了解具体对象如何生产细节,只需要知道生产想要的产品以及对应的工厂。增加新的具体工厂和产品族很方便,无须修改原有系统,符合“开闭原则”。另外,相比于工厂方法模式,抽象工厂模式更为抽象且更具一般性,功能更加强大。工厂方法模式只能生产一个产品族的产品,每个具体工厂生产具体的某种产品。抽象工厂模式能够生产多个产品族的产品,每个具体工厂能够生产一个产品族的产品。

抽象工厂模式在添加新的产品族时十分方便,然而在添加新的产品等级结构时较为繁琐。在抽象工厂中已经声明了所有可能要生产的产品的生产接口,若要使得系统能生产新种类的产品,就要扩展接口,这将涉及到抽象工厂类以及原有的具体工厂类的修改。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值