C++设计模式 --1.工厂模式和单例模式

1.工厂模式

简单工厂模式

抽象产品类

//定义一个抽象水果类 --抽象产品角色
class AbstractFruit
{
    
    
public:
	virtual void showFruitName()=0;//抽取出产品的公共行为, 纯虚函数
    virtual ~AbstractFruit(){
    
    };//虚析构函数  -- 做为顶层基类,一定要显示定义虚析构函数,防止内存溢出
};

具体产品类

//苹果类 -- 具体产品角色
class Apple : public AbstractFruit
{
    
    
public:
	virtual void showFruitName() override {
    
    
		cout << "this is an apple" <<endl;
	}
};

//鸭梨类 -- 具体产品角色
class Pear : public AbstractFruit
{
    
    
public:
	virtual void showFruitName() override {
    
    
		cout << "this is a pear" <<endl;
	}
};

//香蕉类 -- 具体产品角色
class Banana : public AbstractFruit
{
    
    
public:
	virtual void showFruitName() override {
    
    
		cout << "create bananas" <<endl;
	}
};

工厂

//工厂类 --工厂角色
/*
	1.内含一个生成具体产品对象的静态方法,根据传入的参数判断要生成的哪种产品,并返回对象指针
	2.通过抽象产品类类型指针来接收具体产品的堆内存地址,达到多态目的。
*/
class FruitFactory
{
    
    
public:
	static AbstractFruit* makeFruit(string fruitType){
    
    
		if(fruitType == "apple"){
    
    
			return new Apple;
		}else if(fruitType == "pear") {
    
    
			return new Pear;
		}else if(fruitType == "banana") {
    
    
			return new Banana;
		}else {
    
    
			return nullptr;
		}
	}
};

客户端

//客户端
/*
  1.通过工厂类调用其创建产品的静态方法,并根据传入的参数 生成具体的产品对象
*/
int main(int argc, char *argv[])
{
    
    
	AbstractFruit* fruit = FruitFactory::makeFruit("apple");
	if(fruit != nullptr)
		fruit->showFruitName();
	delete fruit;
	cout << "==============" <<endl;
	fruit = FruitFactory::makeFruit("banana");
	if (fruit != nullptr)
		fruit->showFruitName();
	delete fruit;
	return 0;
}

在这里插入图片描述
简单工厂模式不属于 GoF的23种设计模式。
简单工厂模式 有以下三种角色:
抽象产品角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品角色:简单工厂模式所创建的具体实例对象。
工厂角色:简单工厂模式的核心,它负责创建所有实例的内部逻辑,工厂类可以被外界直接调用,创建所需的产品对象。

优点
1.实现客户端和具体实现类解耦;不需要关注对象的创建细节;
2.通过客户端 传入参数 让工厂知道应该创建什么类型对象。
缺点
1.当每增加新类型的具体产品时,需要修改工厂类的中if…else 源代码,不符合开闭原则。
2.这个类过重(很多if…else,及负责生成所有产品),将各种产品对象的初始化集中在一个类中实现,违反了 单一职责原则;
3.并且这个类发生问题,会影响很多使用这个工厂的模块。

简单工厂模式 UML类图:
在这里插入图片描述

工厂方法模式

工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统不修改具体工厂角色的情况下引进新的产品。

工厂方法模式是 简单工厂模式 + 开闭原则 +单一职责原则。
工厂方法模式有以下四个角色:
1.抽象工厂角色:工厂方法模式的核心,负责定义公共接口,任何具体工厂类都必须实现这个接口。
2.具体工厂角色:具体工厂是抽象工厂的一个实现,负责实例化产品对象。
3.抽象产品角色:工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
4.具体产品角色:工厂方法模式所创建的具体实例对象。
工厂方法模式的优点:

  1. 符合开闭原则,即抽象工厂中的公共接口是闭的,针对新种类产品,可以通过增加具体工厂来生产,这个是开的,实现可扩展。
  2. 符合单一职责原则,即每个具体工厂只负责生产某一种类的产品。而不像简单工厂模式中在 工厂类中负责生成所有种类产品。
    工厂方法模式的缺点:
  3. 类的成本个数增加,导致类越来越多,增加维护成本。

代码案例:
抽象工厂

//抽象水果工厂
class AbstractFruitFactory
{
    
    
public:
	virtual AbstractFruit* makeFruit() = 0;//生产水果的纯虚函数(也叫接口)
	virtual ~AbstractFruitFactory(){
    
    };
};

具体工厂

//负责具体生产苹果的苹果工厂
class AppleFactory : public AbstractFruitFactory
{
    
    
public:
	AbstractFruit* makeFruit() //实现接口
	{
    
    
		return new Apple;
	}
};
//负责具体生产鸭梨的鸭梨工厂
class PearFactory : public AbstractFruitFactory
{
    
    
public:
	AbstractFruit* makeFruit() //实现接口
	{
    
    
		return new Pear;
	}
};

//负责具体生产香蕉的香蕉工厂
class BananaFactory : public AbstractFruitFactory
{
    
    
public:
	AbstractFruit* makeFruit() //实现接口
	{
    
    
		return new Banana;
	}
};

抽象产品

//抽象产品
class AbstractFruit
{
    
    
public:
	virtual void showFruitName()=0;
    virtual ~AbstractFruit(){
    
    };
};

具体产品

//苹果类
class Apple : public AbstractFruit
{
    
    
public:
	void showFruitName()
	{
    
    
		cout << "this is an apple" << endl;
	}
};
//鸭梨类
class Pear : public AbstractFruit
{
    
    
public:
	void showFruitName()
	{
    
    
		cout << "this is a pear" << endl;
	}
};
//香蕉类
class Banana : public AbstractFruit
{
    
    
public:
	void showFruitName()
	{
    
    
		cout << "this is a banana" << endl;
	}
};

客户端调用:

//客户端 --调用
int main(int argc, char *argv[])
{
    
    	
	//创建一个抽象工厂类型指针变量
	AbstractFruitFactory* abstractFruitFactory = nullptr;
	//创建一个抽象产品类型指针变量
	AbstractFruit* abstractFruit = nullptr;
	
	//创建生产具体某种产品的工厂类(苹果类),让抽象工厂类型指针指向具体工厂类的对象,从而实现多态
	abstractFruitFactory = new AppleFactory;
	abstractFruit = abstractFruitFactory->makeFruit();

	abstractFruit->showFruitName();

	delete abstractFruitFactory;
	delete abstractFruit;

	cout << "=====================" << endl;
	
	//创建生产具体某种产品的工厂类(鸭梨类),让抽象工厂类型指针指向具体工厂类的对象,从而实现多态
	abstractFruitFactory = new PearFactory;
	abstractFruit = abstractFruitFactory->makeFruit();

	abstractFruit->showFruitName();
	
	delete abstractFruitFactory;
	delete abstractFruit;

	cout << "=====================" << endl;

	//创建生产具体某种产品的工厂类(香蕉类),让抽象工厂类型指针指向具体工厂类的对象,从而实现多态
	abstractFruitFactory = new BananaFactory;
	abstractFruit = abstractFruitFactory->makeFruit();

	abstractFruit->showFruitName();

	delete abstractFruitFactory;
	delete abstractFruit;
	
	return 0;
}

在这里插入图片描述
工厂方法模式UML类图:
在这里插入图片描述

抽象工厂模式

抽象工厂针对的是产品族,而不是产品等级结构。
在这里插入图片描述
抽象工厂模式和工厂方法模式一样也有以下四个角色:
1.抽象工厂角色:抽象工厂模式的核心,负责定义公共接口,任何具体工厂类都必须实现这个接口。
2.具体工厂角色:具体工厂是抽象工厂的一个实现,负责实例化同一产品族的对象。
3.抽象产品角色:抽象工厂模式所创建的相同产品等级对象的父类,它负责描述所有相同产品等级实例所共有的公共接口。
4.具体产品角色:抽象工厂模式所创建的具体实例对象。

可以说 抽象工厂模式是工厂方法模式的升级版。抽象工厂模式指针的是产品族符合开闭原则,而工厂方法模式针对的是多个系列产品符合开闭原则。

代码演示实例:
抽象产品

//抽象苹果类
class AbstractApple
{
    
    
public:
	virtual void showName() = 0;
	virtual ~AbstractApple(){
    
    };
};

//抽象鸭梨类
class AbstractPear
{
    
    
public:
	virtual void showName() = 0;
	virtual ~AbstractPear() {
    
    };
};

//抽象香蕉类
class AbstractBanana
{
    
    
public:
	virtual void showName() = 0;
	virtual ~AbstractBanana() {
    
    };
};

具体产品`:

//中国苹果
class ChinaApple : public AbstractApple
{
    
    
public:
	void showName()
	{
    
    
		cout << "this is a ChinaApple" << endl;	
	}
};

//中国鸭梨
class ChinaPear : public AbstractPear
{
    
    
public:
	void showName()
	{
    
    
		cout << "this is a ChinaPear" << endl;
	}
};

//中国香蕉
class ChinaBanana : public AbstractBanana
{
    
    
public:
	void showName()
	{
    
    
		cout << "this is a ChinaBanana" << endl;
	}
};


//美国苹果
class AmericaApple : public AbstractApple
{
    
    
public:
	void showName()
	{
    
    
		cout << "this is an AmericaApple" << endl;
	}
};


//美国鸭梨
class AmericaPear : public AbstractPear
{
    
    
public:
	void showName()
	{
    
    
		cout << "this is an AmericaPear" << endl;	
	}
};

//美国香蕉
class AmericaBanana : public AbstractBanana
{
    
    
public:
	void showName()
	{
    
    
		cout << "this is an AmericaBanana" << endl;
	}
};

//日本苹果
class JapanApple : public AbstractApple
{
    
    
public:
	void showName()
	{
    
    
		cout << "this is a JapanApple" << endl;
	}
};

//日本鸭梨
class JapanPear : public AbstractPear
{
    
    
public:
	void showName()
	{
    
    
		cout << "this is a JapanPear" << endl;
	}
};

//日本香蕉
class JapanBanana : public AbstractBanana
{
    
    
public:
	void showName()
	{
    
    
		cout << "this is a JapanBanana" << endl;
	}
};

抽象工厂:

//抽象工厂类
class AbstractFruitFactory
{
    
    
public:
	virtual AbstractApple * createApple() = 0;
	virtual AbstractPear * createPear() = 0;
	virtual AbstractBanana * createBanana() = 0;
	virtual ~AbstractFruitFactory(){
    
    };
};

具体工厂:

//中国工厂
class ChinaFruitFactory : public AbstractFruitFactory
{
    
    
public:
	AbstractApple * createApple()
	{
    
    
		return new ChinaApple;
	};

	AbstractPear * createPear()
	{
    
    
		return new ChinaPear;
	};

	AbstractBanana* createBanana()
	{
    
    
		return new ChinaBanana;
	};
};

//美国工厂
class AmericaFruitFactory  : public AbstractFruitFactory
{
    
    
public:
	AbstractApple * createApple()
	{
    
    
		return new AmericaApple;
	};

	AbstractPear * createPear()
	{
    
    
		return new AmericaPear;
	};

	AbstractBanana* createBanana()
	{
    
    
		return new AmericaBanana;
	};
};

//日本工厂
class JapanFruitFactory : public AbstractFruitFactory
{
    
    
public:
	AbstractApple* createApple()
	{
    
    
		return new JapanApple;
	};

	AbstractPear* createPear()
	{
    
    
		return new JapanPear;
	};

	AbstractBanana* createBanana()
	{
    
    
		return new JapanBanana;
	};
};

封装的测试函数:

void testAbstractFactory() {
    
    
	AbstractFruitFactory* abstractFruitFactory = nullptr;
	AbstractApple* apple = nullptr;
	AbstractPear* pear = nullptr;
	AbstractBanana* banana = nullptr;

	abstractFruitFactory = new ChinaFruitFactory;
	apple = abstractFruitFactory->createApple();
	apple->showName();
	pear = abstractFruitFactory->createPear();
	pear->showName();
	banana = abstractFruitFactory->createBanana();
	banana->showName();

	delete abstractFruitFactory;
	delete apple;
	delete pear;

	cout << "=======================" << endl;

	abstractFruitFactory = new AmericaFruitFactory;
	apple = abstractFruitFactory->createApple();
	apple->showName();
	pear = abstractFruitFactory->createPear();
	pear->showName();
	banana = abstractFruitFactory->createBanana();
	banana->showName();

	delete abstractFruitFactory;
	delete apple;
	delete pear;

	cout << "=======================" << endl;

	abstractFruitFactory = new JapanFruitFactory;
	apple = abstractFruitFactory->createApple();
	apple->showName();
	pear = abstractFruitFactory->createPear();
	pear->showName();
	banana = abstractFruitFactory->createBanana();
	banana->showName();

	delete abstractFruitFactory;
	delete apple;
	delete pear;
}

客户端--调用

int main(int argc, char *argv[])
{
    
    
	testAbstractFactory();
	return 0;
}

在这里插入图片描述
抽象工厂模式UML类图:
在这里插入图片描述

2.单例模式

懒汉式

代码示例如下:

LazySingleton类

//懒汉式
#include <iostream>
using namespace std;

class LazySingleton
{
    
    
private:
	LazySingleton(){
    
    cout << "LazySingleton constructor" << endl;};//私有化构造函数
	~LazySingleton(){
    
    };//私有化析构函数
public:
	static LazySingleton* getSingleton()
	{
    
    
		if(singleton == nullptr)
		{
    
    
			cout << "生成单例对象" << endl;
			singleton = new LazySingleton;
		}
		return singleton;
	}

private:
	static LazySingleton* singleton;//声明
};

//定义静态成员变量
LazySingleton*  LazySingleton::singleton = nullptr; //在main函数执行前会进行静态成员的初始化

测试调用

void testLazySingleton()
{
    
    
	//LazySingleton lazySingleton;			//编译不过,构造函数私有化不能在类定义的外部创建类的实例
	//LazySingleton* p1 = new LazySingleton;//编译不过,因为右值要触发在堆上创建类的实例对象,并调用构造函数初始化
	//LazySingleton* p2;//可以,因为它并不会创建类的对象,只是定义了一个类类型的指针变量

	LazySingleton* f1 = LazySingleton::getSingleton();
	LazySingleton* f2 = LazySingleton::getSingleton();
	if(f1 == f2)
	{
    
    
		cout << "f1 和 f2 指向的内存地址相同" << endl;
	}else {
    
    
		cout << "f1 和 f2 指向的内存地址不相同" << endl;
	}
}
int main(int argc, char *argv[])
{
    
    
	cout << "main function ...." << endl;
	testLazySingleton();
	return 0;
}

编译命令:g++ -std=c++11 singleton.cpp -o singleton
打印输出
在这里插入图片描述

饿汉式

代码示例如下:

HungrySingleton类

#include <iostream>
using namespace std;
class HungrySingleton
{
    
    
private:
	HungrySingleton(){
    
     cout << "HungrySingleton constructor" << endl;};//保证构造函数私有
	~HungrySingleton(){
    
    };//析构函数私有
public:
	static HungrySingleton* getSingleton()
	{
    
    
		return singleton;
	}
private:
	static HungrySingleton* singleton;//声明
};

//定义静态成员变量
HungrySingleton*  HungrySingleton::singleton = new HungrySingleton;//在main函数执行前会进行静态成员的初始化,会调用HungryFactory类的私有构造函数初始化对象
//上面这一句,右值为啥可以写new HungryFactory,因为这句静态成员变量的定义,相当于它仍然在类的作用域范围内。可以访问到私有构造函数。

测试调用

void testHungrySingleton()
{
    
    
	//HungrySingleton hungrySingleton;//编译不过,构造函数私有化不能在类定义的外部创建类的实例
	//HungrySingleton* p3 = new HungrySingleton;//编译不过,同上
	//HungrySingleton* p4;//可以,因为它并不会创建类的对象,只是定义了一个类类型的指针变量

	HungrySingleton* f3 = HungrySingleton::getSingleton();
	HungrySingleton* f4 = HungrySingleton::getSingleton();
	if(f3 == f4)
	{
    
    
		cout << "f3 和 f4 指向的内存地址相同" << endl;
	}else {
    
    
		cout << "f3 和 f4 指向的内存地址不相同" << endl;
	}
}

int main(int argc, char *argv[])
{
    
    
	cout << "main function ...." << endl;
	testHungrySingleton();
	return 0;
}

编译命令:g++ -std=c++11 singleton.cpp -o singleton
打印输出
在这里插入图片描述
懒汉式的特点:
1.私有化构造函数和析构函数。
2.定义一个单例对象的类类型指针的静态成员变量,并指向空地址。
3.提供静态获取单例对象的函数
饿汉式的特点:
1.私有化构造函数和析构函数。
2.定义一个单例对象的类类型指针的静态成员变量,并初始化为单例对象。
3.提供静态获取单例对象的函数。

两者的不同点:
懒汉式 是在程序中首次需要时才进行单例对象的生成,生成的时期是在main函数执行后。
饿汉式 是在程序加载时进行的静态成员变量的初始化生成的,生成的时期是在main函数执行前。
懒汉式 是线性不安全的,而饿汉式是线程安全的。

关于单例对象的内存释放问题:
由于整个程序运行期间 都是公用这个类的一个实例对象。私有化析构函数的目的就是防止人为手动删除单例对象,以至于
别人获取时出现失败。故而不提供公用的析构函数,那么堆内的这个单例对象,只有在程序结束时,由操作系统进行单例
对象内存回收,不用担心会发生内存泄漏,因为这个类的实例对象 自始至终只有一份,占不了多大内存。因为内存泄漏的
发生原因是指的堆中非单例对象,不断地创建新对象,程序不再使用时,也没有手动干预进行堆内存释放。导致日积月
累,堆内存被占用完毕,进而发生堆内存泄漏。
内存泄漏 只发生于 堆内存。这里所说的内存泄漏 都是指的堆内存泄漏。

猜你喜欢

转载自blog.csdn.net/adminstate/article/details/135432714