xiaoxiao-1's Blog

踔厉奋发,极致无憾!

0%

设计模式之单例模式、工厂模式

设计模式之单例模式、工厂模式

在构思如何构造一个工具类,它负责读取一个文件中的所有配置,然后可以被其他对象访问并且读取它内部的配置变量,这边产生了一个矛盾,我不想让它出现其他所有类的内部,因为太冗余了,所以它存储的变量就只能是静态类型,但是这样初始化就会写的非常不优雅。然后了解到了有一类设计模式叫单例模式和工厂模式能够很优雅的解决这个问题。

单例模式

单例模式是一种创建型设计模式,其目的是确保类只有一个实例,并提供一个全局访问点来获取该实例。它解决的主要问题是限制类的实例化,确保在程序中只能存在一个实例,并提供对该实例的全局访问

优点:

  1. 全局访问性:单例模式提供了一个全局访问点,可以在程序的任何地方访问单例实例。
  2. 避免重复实例化:单例模式确保一个类只有一个实例,避免了重复实例化的开销。
  3. 节省资源:由于单例模式只有一个实例,可以节省系统资源,特别是对于需要频繁创建和销毁的对象。
  4. 实现线程安全:合理实现单例模式可以保证线程安全,避免多线程环境下的竞争条件。

缺点:

  1. 违背单一职责原则:单例模式往往将对象的实例化和全局访问耦合在一起,可能导致职责不清晰。
  2. 难以扩展和测试:由于单例模式的全局访问性,扩展和测试单例类的行为可能会变得困难。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Logger {
public:
static Logger& getInstance() {
static Logger instance;
return instance;
}

void log(const std::string& message) {
// 日志记录逻辑
std::cout << "Logging: " << message << std::endl;
}

private:
Logger() {
// 私有构造函数
}

// 禁用拷贝构造函数和赋值运算符
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
};

int main() {
Logger& logger = Logger::getInstance();
logger.log("Hello, world!");

return 0;
}

单例模式还分为懒汉式和饿汉式,他们的区别是:前者在需要时才进行实例化,后者在类加载的过程中完成实例化。前者资源耗费较少,但是会有线程安全问题,后者会造成资源浪费,但是线程安全。

工厂模式

工厂模式(Factory Pattern)是一种很常用的设计模式,主要目的是将对象的创建过程封装起来,降低对象之间的耦合度。

工厂模式的主要特点和作用:

  • 封装了对象的创建过程,将对象的创建和使用分离,降低耦合
  • 客户端不需要知道具体产品类的类名,只需要知道参数,就可以获取产品实例
  • 可以使用一个工厂类创建多个不同但相关的对象,而无需指定具体类名
  • 可以更方便地添加新产品类,客户端不会因为新添加的类而改变代码
  • 实现了开闭原则,增加新的产品类时无需修改原有代码

工厂模式的缺点:

  • 增加了系统的复杂度和理解难度
  • 实现时需要引入许多新的类和对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Shape {
public:
virtual void draw() = 0;
};

class Circle : public Shape {
public:
void draw() override {
// 绘制圆形
}
};

class Square : public Shape {
public:
void draw() override {
// 绘制正方形
}
};

class ShapeFactory {
public:
static Shape* getShape(string type) {
if (type == "circle") {
return new Circle();
} else if (type == "square") {
return new Square();
}

return nullptr;
}
};

// 客户端代码
Shape* shape = ShapeFactory::getShape("circle");
shape->draw();