c++实现工厂模式

1. 背景介绍

参考博客

工厂模式使用场景:

  • 一种是创建过程涉及复杂的 if-else 分支判断,
  • 另一种是对象创建需要组装多个其他类对象或者需要复杂的初始化过程。

2. 不使用工厂

3. 简单工厂实现

#include <bits/stdc++.h>
using namespace std;

enum PRODUCTTYPE {SFJ, XSL, NAS};

/**
 * 肥皂基类,定义协议
 */
class soapBase {
public:
    virtual void show() = 0; //纯虚函数
    virtual ~soapBase() {} //基类析构函数设置为虚函数
};

class SFJSoap : public soapBase {
public:
    void show() {
        cout << "SFJ Soap!" << endl;
    }
};

class XSLSoap : public soapBase {
public:
    void show() {
        cout << "XSL Soap!" << endl;
    }
};

class NASSoap : public soapBase {
public:
    void show() {
        cout << "NAS Soap!" << endl;
    }
};

/**
 * 简单工厂实现,肥皂创建工程,负责对象创建工作
 */
class SoapFactory {
public:
    soapBase *createSoap(PRODUCTTYPE type) {
        switch (type) {
            case SFJ:
                return new SFJSoap();
                break;
            case XSL:
                return new XSLSoap();
                break;
            case NAS:
                return new NASSoap();
                break;
            default:
                cerr << "Type NOT exist!" << endl;
                return nullptr;
                break;
        }
    }
};

int main() {
    SoapFactory factory;
    soapBase* pSoap1 = factory.createSoap(SFJ);
    pSoap1->show();
    soapBase* pSoap2 = factory.createSoap(XSL);
    pSoap2->show();
    soapBase* pSoap3 = factory.createSoap(NAS);
    pSoap3->show();
    return 0;
}

输出结果

SFJ Soap!
XSL Soap!
NAS Soap!

 优点: 对比于直接在主函数中创建对象,通过单独使用工厂类可以使得代码更加清晰,更加符合单一职责原则

缺点:如何要添加新的肥皂品牌就要更改SoapFactory的代码,稍微违反开闭原则(如果少量改动可以接受)

4. 工厂方法实现

#include <bits/stdc++.h>
using namespace std;

enum SOAPTYPE {SFJ, XSL, NAS};

class soapBase {
public:
    virtual ~soapBase() {};
    virtual void show() = 0;
};

class SFJSoap : public soapBase {
public:
    void show() {
        cout << "SFJ Soap!" << endl;
    }
};

class XSLSoap : public soapBase {
public:
    void show() {
        cout << "XSL Soap!" << endl;
    }
};

class NASSoap : public soapBase {
public:
    void show() {
        cout << "NAS Soap!" << endl;
    }
};

/**
 * 工厂基类
 */
class FactoryBase {
public:
    virtual soapBase* createSoap() = 0;
};

class SFJFactory : public FactoryBase {
public:
    soapBase* createSoap() {
        return new SFJSoap();
    }
};

class XSLFactory : public FactoryBase {
public:
    soapBase* createSoap() {
        return new XSLSoap();
    }
};

class NASFactory : public FactoryBase {
public:
    soapBase* createSoap() {
        return new NASSoap();
    }
};

int main() {
    SFJFactory factory1;
    soapBase *pSoap1 = factory1.createSoap();
    pSoap1->show();

    XSLFactory factory2;
    soapBase *pSoap2 = factory2.createSoap();
    pSoap2->show();

    NASFactory factory3;
    soapBase *pSoap3 = factory3.createSoap();
    pSoap3->show();
    
    return 0;
}

输出结果

SFJ Soap!
XSL Soap!
NAS Soap!

 优点:比简单工厂更加符合开闭原则

缺点:代码更加复杂,每次新增一种肥皂除了写肥皂本身类,还要写对应的工厂类,如果不只按照品牌来分类,而且还需要按产地国家进行划分,那就需要写很多代码,这个时候就可以使用下面的抽象工厂方法

5. 抽象工厂实现

#include <bits/stdc++.h>
using namespace std;

enum SOAPTYPE {SFJ, NAS};
enum COUNTRY {CHINA, JAPAN};

class SoapBase {
public:
    virtual ~SoapBase() {};
    virtual void show() = 0;
};

class SFJSoap : public SoapBase {
public:
    void show() {
        cout << "SFJ Soap!" << endl;
    }
};

class NASSoap : public SoapBase {
public:
    void show() {
        cout << "NAS Soap!" << endl;
    }
};

class CountryBase {
public:
    virtual ~CountryBase() {};
    virtual void show() = 0;
};

class China : public CountryBase {
public:
    void show() {
        cout << "Maked in China!" << endl;
    }
};

class Japan : public CountryBase {
public:
    void show() {
        cout << "Maked in Japan!" << endl;
    }
};

class FactoryBase {
public:
    virtual SoapBase* createSoap() = 0;
    virtual CountryBase* createCountry() = 0;
};

class FactoryA : public FactoryBase {
public:
    SoapBase* createSoap() {
        return new SFJSoap();
    }

    CountryBase* createCountry() {
        return new China();
    };
};

class FactoryB : public FactoryBase {
public:
    SoapBase* createSoap() {
        return new NASSoap();
    }

    CountryBase* createCountry() {
        return new Japan();
    }
};

int main() {
    FactoryA factory1;
    SoapBase *pSoap1 = nullptr;
    CountryBase *pCountry1 = nullptr;
    pSoap1 = factory1.createSoap();
    pCountry1 = factory1.createCountry();
    pSoap1->show();
    pCountry1->show();

    FactoryB factory2;
    SoapBase *pSoap2 = nullptr;
    CountryBase *pCountry2 = nullptr;
    pSoap2 = factory2.createSoap();
    pCountry2 = factory2.createCountry();
    pSoap2->show();
    pCountry2->show();
    return 0;
}

优点:如果分类的情况很多,创建对象比较复杂可以使用这种方法,这种情况比工厂方法容易维护,因为相对来说每个工厂类更加单一

缺点:编码很复杂

5. 工厂模式的作用

  • 封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明。
  • 代码复用:创建代码抽离到独立的工厂类之后可以复用。
  • 隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象。
  • 控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁。

6. 工厂方法模式新示例(更推荐)

设计模式学习网站

工厂方法模式

工厂方法模式结构

6.1 概述

  • 用工厂方法代替用于对象构造函数的直接调用(new)
  • 工厂方法返回的对象通常称为产品

6.2 编码

使用智能指针改造源代码

#include <bits/stdc++.h>
using namespace std;

/**
 * 产品抽象类
 */
class Product {
 public:
  virtual ~Product() {}
  virtual string Operation() const = 0;
};

/**
 * 具体产品类1
 */
class ConcreteProduct1 : public Product {
 public:
  string Operation() const override {
    return "{Result of the ConcreteProduct1}";
  }
};

/**
 * 具体产品类2
 */
class ConcreteProduct2 : public Product {
 public:
  string Operation() const override {
    return "{Result of the ConcreteProduct2}";
  }
};

/**
 * 工厂类,抽象类
 */
class Creator {
 public:
  virtual ~Creator(){};
  virtual shared_ptr<Product> FactoryMethod() const = 0;
  string SomeOperation() const {
    shared_ptr<Product> product = FactoryMethod();
    string result = "Creator: The same creator's code has just worked with " + product->Operation();
    return result;
  }
};

/**
 * 工厂子类1
 */
class ConcreteCreator1 : public Creator {
 public:
  shared_ptr<Product> FactoryMethod() const override {
    return make_shared<ConcreteProduct1> ();
  }
};

/**
 * 工厂子类2
 */
class ConcreteCreator2 : public Creator {
 public:
  shared_ptr<Product> FactoryMethod() const override {
    return make_shared<ConcreteProduct2>();
  }
};

/**
 * @brief 客户端代码
 * @param creator 工厂对象引用
 */
void ClientCode(const Creator& creator) {
  cout << "Client: I'm not aware of the creator's class, but it still works.\n"
       << creator.SomeOperation() << endl;
}


int main() {
  cout << "App: Launched with the ConcreteCreator1.\n";
  shared_ptr<Creator> creator = make_shared<ConcreteCreator1>();
  ClientCode(*creator);
  cout << endl;

  cout << "App: Launched with the ConcreteCreator2.\n";
  shared_ptr<Creator> creator2 = make_shared<ConcreteCreator2>();
  ClientCode(*creator2);

  return 0;
}

输出:

App: Launched with the ConcreteCreator1.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct1}

App: Launched with the ConcreteCreator2.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct2}

6.3 总结

工厂有基类,产品有基类,这里的基类是抽象类,尽量依赖抽象而不依赖实现;

但是这里也注意到其实不可能完全不知道工厂子类,在使用工厂创建对象的时候需要指定具体的工厂子类类型,但是后续的客户端可以只依赖于工厂抽象类

7. 抽象工厂模式新示例

7.1 概述

抽象工厂模式

抽象工厂设计模式

多维度的分类,工厂的工厂 

7.2 编码

#include <bits/stdc++.h>
using namespace std;

/**
 * 抽象产品A,对应一个产品系列
 */
class AbstractProductA {
 public:
  virtual ~AbstractProductA() {};
  virtual string UsefulFunctionA() const = 0;
};

/**
 * A系列的具体产品A1
 */
class ConcreteProductA1 : public AbstractProductA {
 public:
  string UsefulFunctionA() const override {
    return "The result of the product A1.";
  }
};

/**
 * A系列的具体产品A2
 */
class ConcreteProductA2 : public AbstractProductA {
  string UsefulFunctionA() const override {
    return "The result of the product A2.";
  }
};

/**
 * 产品产品B,对应另外一个产品系列
 */
class AbstractProductB {
 public:
  virtual ~AbstractProductB(){};
  virtual string UsefulFunctionB() const = 0;
  // 与A系列产品的协作
  virtual string AnotherUsefulFunctionB(const AbstractProductA& collaborator) const = 0;
};

/**
 * B系列具体产品B1
 */
class ConcreteProductB1 : public AbstractProductB {
 public:
  string UsefulFunctionB() const override {
    return "The result of the product B1.";
  }
  string AnotherUsefulFunctionB(const AbstractProductA& collaborator) const override {
    const string result = collaborator.UsefulFunctionA();
    return "The result of the B1 collaborating with ( " + result + " )";
  }
};

/**
 * B系列具体产品B2
 */
class ConcreteProductB2 : public AbstractProductB {
 public:
  string UsefulFunctionB() const override {
    return "The result of the product B2.";
  }

  string AnotherUsefulFunctionB(const AbstractProductA& collaborator) const override {
    const string result = collaborator.UsefulFunctionA();
    return "The result of the B2 collaborating with ( " + result + " )";
  }
};

/**
 * 抽象工厂类
 */
class AbstractFactory {
 public:
  virtual shared_ptr<AbstractProductA> CreateProductA() const = 0;
  virtual shared_ptr<AbstractProductB> CreateProductB() const = 0;
};

/**
 * 具体工厂类1
 */
class ConcreteFactory1 : public AbstractFactory {
 public:
  shared_ptr<AbstractProductA> CreateProductA() const override {
    return make_shared<ConcreteProductA1>();
  }
  shared_ptr<AbstractProductB> CreateProductB() const override {
    return make_shared<ConcreteProductB1>();
  }
};

/**
 * 具体工厂类2
 */
class ConcreteFactory2 : public AbstractFactory {
 public:
  shared_ptr<AbstractProductA> CreateProductA() const override {
    return make_shared<ConcreteProductA2>();
  }
  shared_ptr<AbstractProductB> CreateProductB() const override {
    return make_shared<ConcreteProductB2>();
  }
};

void ClientCode(const AbstractFactory &factory) {
  shared_ptr<const AbstractProductA> product_a = factory.CreateProductA();
  shared_ptr<const AbstractProductB> product_b = factory.CreateProductB();
  cout << product_a->UsefulFunctionA() << endl;
  cout << product_b->UsefulFunctionB() << endl;
}

int main() {
  cout << "Client: Testing client code with the first factory type" << endl;
  shared_ptr<ConcreteFactory1> f1 = make_shared<ConcreteFactory1>();
  ClientCode(*f1);
  cout << endl;

  cout << "Client: Testing the same client code with the second factory type" << endl;
  shared_ptr<ConcreteFactory2> f2 = make_shared<ConcreteFactory2>();
  ClientCode(*f2);

  return 0;
}

输出:

Client: Testing client code with the first factory type
The result of the product A1.
The result of the product B1.

Client: Testing the same client code with the second factory type
The result of the product A2.
The result of the product B2.

 客户端代码可以重复利用

7.3 总结

优点:

  • 更加符合单一职责原则
  • 更加符合开闭原则
  • 减少客户端和具体产品代码耦合

缺点:

  • 编码复杂

对比简单工厂、工厂方法、抽象工厂总结

对比工厂

  • 简单工厂:大多数情况下,简单工厂是工厂方法或抽象工厂的中间步骤,简单工厂类通常没有子类,当从简单工厂中提取出子类后,它更像工厂方法模式了
  • 工厂方法:创建型设计模式,存在工厂基类和子类
  • 抽象工厂:创建型设计模式,工厂方法解决的是根据一种分类方法(一种角度的扩展),设计一种模式解决它们的对象创建问题,而抽象工厂模式适用于不只一种分类方法(多种角度的扩展)。比如说现在要创建交通运输工具对象,按照形态分为汽车;按照发动类型分为内燃机和喷气式发动机;按照控制方式分为方向盘和操纵杆,那么就可以使用抽象工厂,抽象工厂又被称为工厂的工厂
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值