1、创建型模式(常见的设计模式)
Factory 模式(工厂模式,被实例化的子类)
在面向对象系统设计中经常可以遇到以下的两类问题:
下面是第一类问题和代码示例:我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。所以就不得不在要用到子类的地方写new 对象。这样实体类的使用者必须知道实际的子类名称,以及会使程序的扩展性和维护变得越来越困难。
- #include
-
- // 抽象基类或接口
- class Animal {
- public:
- virtual void makeSound() = 0; // 纯虚函数
- };
-
- // 具体子类
- class Dog : public Animal {
- public:
- void makeSound() override {
- std::cout << "Woof!" << std::endl;
- }
- };
-
- class Cat : public Animal {
- public:
- void makeSound() override {
- std::cout << "Meow!" << std::endl;
- }
- };
-
- int main() {
- Animal* animal;
-
- // 通过指向基类的指针指向具体的子类实例
- animal = new Dog();
- animal->makeSound();
-
- animal = new Cat();
- animal->makeSound();
-
- return 0;
- }
在上述示例中,我们定义了一个抽象基类 Animal,其中包含一个纯虚函数 makeSound()。然后我们派生出两个具体的子类 Dog 和 Cat,并分别实现了 makeSound() 方法。在 main() 函数中,我们使用指向基类的指针 animal,通过 new 实例化具体的子类,并调用其方法。这样可以实现多态性,但使用者需要知道具体的子类名称,不利于程序的扩展性和维护。
还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。只能在父类中写方法调用,具体调用哪一个类的方法交给子类实现。
- #include
-
- // 抽象基类
- class Animal {
- public:
- virtual void makeSound() = 0; // 纯虚函数
-
- void performAction() {
- std::cout << "Performing action: ";
- makeSound();
- }
- };
-
- // 具体子类
- class Dog : public Animal {
- public:
- void makeSound() override {
- std::cout << "Woof!" << std::endl;
- }
- };
-
- class Cat : public Animal {
- public:
- void makeSound() override {
- std::cout << "Meow!" << std::endl;
- }
- };
-
- int main() {
- Animal* animal = nullptr;
- int choice;
-
- std::cout << "Enter 1 for Dog, 2 for Cat: ";
- std::cin >> choice;
-
- // 根据用户的选择实例化不同的子类
- if (choice == 1) {
- animal = new Dog();
- } else if (choice == 2) {
- animal = new Cat();
- } else {
- std::cout << "Invalid choice" << std::endl;
- return 0;
- }
-
- animal->performAction();
-
- delete animal;
-
- return 0;
- }
在上述示例中,我们仍然有一个抽象基类 Animal,其中包含一个纯虚函数 makeSound()。不同之处在于,在 Animal 类中我们添加了一个 performAction() 方法,该方法调用了 makeSound() 方法。在 main() 函数中,根据用户的选择实例化不同的子类,并通过基类指针调用 performAction() 方法。这样,具体调用哪个子类的方法由子类自己实现,父类并不知道具体的子类实例化。
以上两个问题也就引出了 Factory 模式的两个最重要的功能:
1)定义创建对象的接口,封装了对象的创建。
2)使得具体化类的工作延迟到了子类中。
工厂模式代码示例
- #include
- #include
-
- // 抽象产品类
- class Product {
- public:
- virtual void use() const = 0;
- };
-
- // 具体产品类 A
- class ConcreteProductA : public Product {
- public:
- void use() const override {
- std::cout << "Using ConcreteProductA" << std::endl;
- }
- };
-
- // 具体产品类 B
- class ConcreteProductB : public Product {
- public:
- void use() const override {
- std::cout << "Using ConcreteProductB" << std::endl;
- }
- };
-
- // 工厂类
- class Factory {
- public:
- virtual Product* createProduct() const = 0;
-
- Product* getProduct() const {
- Product* product = createProduct();
- // 可以在这里添加其他的初始化逻辑
- return product;
- }
- };
-
- // 具体工厂类 A
- class ConcreteFactoryA : public Factory {
- public:
- Product* createProduct() const override {
- return new ConcreteProductA();
- }
- };
-
- // 具体工厂类 B
- class ConcreteFactoryB : public Factory {
- public:
- Product* createProduct() const override {
- return new ConcreteProductB();
- }
- };
-
- int main() {
- Factory* factory = nullptr;
- Product* product = nullptr;
- std::string choice;
-
- std::cout << "Enter A for ConcreteProductA, B for ConcreteProductB: ";
- std::cin >> choice;
-
- // 根据用户的选择实例化不同的具体工厂类
- if (choice == "A") {
- factory = new ConcreteFactoryA();
- } else if (choice == "B") {
- factory = new ConcreteFactoryB();
- } else {
- std::cout << "Invalid choice" << std::endl;
- return 0;
- }
-
- // 使用工厂类创建产品对象
- product = factory->getProduct();
- product->use();
-
- delete factory;
- delete product;
-
- return 0;
- }
AbstactFactory 模式 (产品对象家族)
假如我们要买水果,水果的产地来自中国、日本、美国,每个国家的水果种类都可以分为苹果、香蕉、梨子。作为开发者,我们就不得不创建苹果类(香蕉和梨子类似),然后每种苹果都继承自苹果类。每上架一个国家的苹果我们都要实现一次苹果类,这样就会有成千上万的苹果类需要被创建,AbstractFactory 模式就是用来解决这类问题的:要创建一组相关或者相互依赖的对象。
- //抽象工厂模式
- #include
- using namespace std;
-
- //苹果的抽象
- class AbstractApple {
- public:
- virtual void showName() = 0;
- };
-
- //中国苹果
- class ChinaApple :public AbstractApple {
- public:
- virtual void showName() {
- cout << "中国苹果" << endl;
- }
- };
-
- //美国苹果
- class USAApple :public AbstractApple {
- public:
- virtual void showName() {
- cout << "美国苹果" << endl;
- }
- };
-
- //日本苹果
- class JapanApple :public AbstractApple {
- public:
- virtual void showName() {
- cout << "日本苹果" << endl;
- }
- };
-
- //香蕉的抽象
- class AbstractBanana {
- public:
- virtual void showName() = 0;
- };
-
- //中国香蕉
- class ChinaBanana :public AbstractBanana {
- public:
- virtual void showName() {
- cout << "中国香蕉" << endl;
- }
- };
-
- //美国香蕉
- class USABanana :public AbstractBanana {
- public:
- virtual void showName() {
- cout << "美国香蕉" << endl;
- }
- };
-
- //日本香蕉
- class JapanBanana :public AbstractBanana {
- public:
- virtual void showName() {
- cout << "日本香蕉" << endl;
- }
- };
-
- //鸭梨的抽象
- class AbstractPear {
- public:
- virtual void showName() = 0;
- };
-
- //中国鸭梨
- class ChinaPear :public AbstractPear {
- public:
- virtual void showName() {
- cout << "中国鸭梨" << endl;
- }
- };
-
- //美国鸭梨
- class USAPear :public AbstractPear {
- public:
- virtual void showName() {
- cout << "美国鸭梨" << endl;
- }
- };
-
- //日本鸭梨
- class JapanPear :public AbstractPear {
- public:
- virtual void showName() {
- cout << "日本鸭梨" << endl;
- }
- };
-
- //抽象工厂 针对产品族
- class AbstractFactory {
- public:
- virtual AbstractApple* CreateApple() = 0;
- virtual AbstractBanana* CreateBanana() = 0;
- virtual AbstractPear* CreatePear() = 0;
- };
-
- //中国工厂
- class ChinaFactory :public AbstractFactory {
- virtual AbstractApple* CreateApple() {
- return new ChinaApple;
- }
- virtual AbstractBanana* CreateBanana() {
- return new ChinaBanana;
- }
- virtual AbstractPear* CreatePear() {
- return new ChinaPear;
- }
- };
-
- //美国工厂
- class USAFactory :public AbstractFactory {
- virtual AbstractApple* CreateApple() {
- return new USAApple;
- }
- virtual AbstractBanana* CreateBanana() {
- return new USABanana;
- }
- virtual AbstractPear* CreatePear() {
- return new USAPear;
- }
- };
-
- //日本工厂
- class JapanFactory :public AbstractFactory {
- virtual AbstractApple* CreateApple() {
- return new JapanApple;
- }
- virtual AbstractBanana* CreateBanana() {
- return new JapanBanana;
- }
- virtual AbstractPear* CreatePear() {
- return new JapanPear;
- }
- };
-
- void test01() {
- AbstractFactory* factory = NULL;
- AbstractApple* apple = NULL;
- AbstractBanana* Banana = NULL;
- AbstractPear* Pear = NULL;
-
- //中国工厂
- factory = new ChinaFactory;
- apple = factory->CreateApple();
- Banana = factory->CreateBanana();
- Pear = factory->CreatePear();
-
- apple->showName();
- Banana->showName();
- Pear->showName();
-
- delete Pear;
- delete apple;
- delete Banana;
- delete factory;
- }
-
- int main()
- {
- test01();
- }
-
Singleton 模式( 单例模式,针对一个类的唯一实例)
Singleton 模式是设计模式中最为简单、最为常见、最容易实现,也是最应该熟悉和掌握的模式。Singleton 模式就是一个类只创建一个唯一的对象,即一次创建多次使用。
实现单例模式的步骤:
1、构造函数私有化
2、增加静态私有的当前类的指针变量
3、提供静态对外接口,可以让用户获得单例对象
单例分为懒汉式和饿汉式
懒汉式:解决了饿汉式内存浪费问题,但是线程不安全的,可以通过互斥量mutex.lock()和mutex.unlock()来解决,懒汉用的比较多
饿汉式:还没有使用该单例对象,该单例对象就已经被加载到内存了,在对象过多时会造成内存浪费,饿汉模式会在程序启动时就创建单例对象,并且该对象会一直存在于内存中,即使在程序执行过程中没有被使用。这可能会导致内存浪费,特别是在单例对象比较大或者创建单例对象需要消耗大量资源的情况下。
这个是饿汉模式,返回的是一个静态变量,静态变量没运行就会产生数据
- class Singleton {
- private:
- static Singleton instance;
-
- Singleton() {}
-
- public:
- static Singleton& getInstance() {
- return instance;
- }
-
- void doSomething() {
- std::cout << "Singleton instance is doing something." << std::endl;
- }
- };
-
- Singleton Singleton::instance;
-
- int main() {
- Singleton& singleton = Singleton::getInstance();
- singleton.doSomething();
-
- return 0;
- }
这个是懒汉模式,返回的是一个静态变量指针,程序调用getinstance才会产生数据
- #include
- #include
-
- class Singleton {
- private:
- //类外定义成员变量
- static Singleton* instance;
- static std::mutex mutex;
- //构造函数私有化
- Singleton() {}
-
- public:
- static Singleton* getInstance() {
- if (instance == nullptr) {
- std::lock_guard
lock(mutex) ; - if (instance == nullptr) {
- instance = new Singleton();
- }
- }
- return instance;
- }
-
- void doSomething() {
- std::cout << "Singleton instance is doing something." << std::endl;
- }
- };
-
- Singleton* Singleton::instance = nullptr;
- std::mutex Singleton::mutex;
-
- int main() {
- Singleton* singleton = Singleton::getInstance();
- singleton->doSomething();
-
- return 0;
- }