1、创建型模式
主要关注点是:“怎样创建对象?”
主要特点是:“将对象的创建与使用分离”
这样使用者不需要关注对象的创建细节,对象的创建由相应的工厂实现。
(隐藏了对象如何被创建和组合在一起)
包括五种:
简单工厂模式(Simple Factory)
工厂方法模式(Factory Method)
抽象工厂模式(Abstract Factory)
建造者模式(Builder)
单例模式(Singleton)
2、简单工厂模式
2.1 定义
简单工厂模式(Simple Factory Pattern)因为内部使用静态方法根据不同参数构造不同产品对象实例,也称静态工厂方法模式。
在简单工厂模式中,可以根据参数的不同返回不同实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
2.2 模式结构
- 工厂角色:工厂角色负责实现创建所有实例的内部逻辑。工厂类内部提供静工厂方法,用于创建所需产品对象,可被外界直接调用。
- 抽象产品角色:抽象产品角色是所创建的所有对象的父类,负责描述所有的实例所共有的公共接口。抽象产品是工厂类创建创建的所有对象的父类或共有的接口,封装各种产品对象的公有方法。
- 具体产品角色:具体产品角色是创建目标,所有的创建的对象都充当这个角色的某个具体类的实例。每个具体产品都继承了抽象产品角色,实现抽象产品角色中的抽象方法。

2.3 C++代码
简单工厂模式的核心是,对于一个父类的多个继承子类,工厂对象的工厂函数根据用户输入,自动new出一个子类对象并返回其父类的指针,这样利用父类的指针执行父类的虚函数,就可以动态绑定子类的重写函数,从而实现多态。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
//抽象产品类-操作
class Operation
{
private:
double A, B;
public:
Operation() :A(0), B(0) {}
double GetA() const { return A; }
double GetB() const { return B; }
void SetA(double x) { A = x; }
void SetB(double y) { B = y; }
virtual double GetResult() = 0;
/*
double GetA() const{return A;}中的const:
只有函数是一个类的非静态成员函数才可以。
类的非静态成员函数不管有几个参数,都会隐形的传入一个参数this
this是指向该类的指针,加了const以后,表示不可以更改这个对象的成员变量。
如return A++; 编译的时候就会报错。其实是A是this->A
*/
};
//具体产品类-加法
class Add :public Operation
{
public:
double GetResult() { return GetA() + GetB(); }
};
//具体产品类-减法
class Sub :public Operation
{
public:
double GetResult() { return GetA() - GetB(); }
};
//具体产品类-乘法
class Mul :public Operation
{
public:
double GetResult() { return GetA()*GetB(); }
};
//具体产品类-除法
class Div :public Operation
{
public:
double GetResult() { return GetA() / GetB(); }
};
//工厂类
class SimpleFactory
{
public:
static Operation* CreateOperator(char ch)
{
Operation* p=NULL;
switch (ch)
{
case '+':
p = new Add();
break;
case '-':
p = new Sub();
break;
case '*':
p = new Mul();
break;
case '/':
p = new Div();
break;
}
return p;
}
};
int main()
{
double A = 0;
double B = 0;
char ch= '\0';
cin >> A >> ch >> B;
Operation* op=SimpleFactory::CreateOperator(ch);
op->SetA(A);
op->SetB(B);
cout << op->GetResult() << endl;
delete op;
return 0;
}
2.4 模式分析
- 调用工厂类的工厂方法时,由于工厂方法时静态方法,可以通过类名直接调用,而且只需要传入一个简单的参数即可。
- 但是它破坏了开闭原则(即只添加不修改)。当想要添加对象类型,例如想添加“^”的运算,则需要添加一个乘方类并且需要修改简单工厂类。
- 将对象的创建和对象业务处理分离可以降低系统的耦合度,使得二者修改起来都相对容易。
- 要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无需知道其创建细节。
2.5 优点
- 客户端不需要创建产品对象,仅仅消费对象即可;简单工厂模式通过这种做法实现了对责任的分割。
- 无需知道具体产品类的类名,只需要知道对应的参数即可。
- 通过引入配置文件,可以在不需要修改任何客户端代码的情况下更新和增加具体的产品类,提高了系统的灵活性
2.6 缺点
- 工厂类集中所有产品的创建逻辑,一旦不能正常工作,整个系统都要受到影响。
- 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
- 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
- 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
2.7 适用环境
- 工厂类负责创建的对象比较少:由于创建的对象比较少,不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不关心创建细节,甚至连类名都不需要记住,只需要记住类型所对应的参数。
3、工厂模式
3.1 定义
现在对系统进行修改,不再设计一个按钮工厂类来统一负责所有产品的创建,而是将具体按钮的创建过程交给专门的工厂子类去完成。
在工厂方法模式中,工厂父类定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象。
这样子做的目的时将产品类的实例操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
3.2 模式结构
- 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
- 抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
- 具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

3.3 C++代码
#include <iostream>
using namespace std;
//抽象产品
class Product
{
public:
virtual void show() = 0;
};
//具体产品1
class ConcreteProduct1 :public Product
{
public:
void show()
{
cout << "具体产品1" << endl;
}
};
//具体产品2
class ConcreteProduct2 :public Product
{
public:
void show()
{
cout << "具体产品2" << endl;
}
};
//抽象工厂
class AbstractFactory
{
public:
virtual Product* newProduct() = 0;
};
//具体工厂1
class ConcreteFactory1 :public AbstractFactory
{
public:
Product* newProduct()
{
return new ConcreteProduct1();
}
};
//具体工厂2
class ConcreteFactory2 :public AbstractFactory
{
public:
Product* newProduct()
{
return new ConcreteProduct2();
}
};
int main()
{
ConcreteFactory1 cf_1;
Product *pd_1 = cf_1.newProduct();
pd_1->show();
ConcreteFactory2 cf_2;
Product *pd_2 = cf_2.newProduct();
pd_2->show();
delete pd_1,pd_2;
return 0;
}

#include <iostream>
#include <string>
using namespace std;
//抽象产品
class Log
{
private :
string name;
public:
string getName() { return name; }
void setName(string name) { this->name = name; }
virtual void writeLog() = 0;
};
//具体产品
class FileLog :public Log
{
public:
void writeLog()
{
cout << this->getName() << endl;
}
};
class DatabaseLog :public Log
{
public:
void writeLog()
{
cout << this->getName() << endl;
}
};
//抽象工厂
class LogFactory
{
public:
virtual Log* createLog(string log)throw(int, string);
};
//具体工厂
class FileLogFactory :public LogFactory
{
public:
Log* createLog(string log)throw(int) {
return new FileLog();
}
};
//具体工厂
class DatabaseFactory :public LogFactory
{
public:
Log* createLog(string log)throw(string)
{
return new DatabaseLog();
}
};
Log * LogFactory::createLog(string log) throw(int, string)
{
return nullptr;
}
class Client
{
public:
static void main()throw (int, string) {
LogFactory* a = new FileLogFactory();
Log* b = a->createLog("filelog");
b->setName("filelog");
b->writeLog();
delete a, b;
}
};
int main(){
Client c;
c.main();
return 0;
}
3.4 模式分析
使用面向对象的多态性
这个核心的工厂类不再负责所有产品的创建,而是将具体的创建工作去做。这个核心类只负责给出具体工厂必须实现的接口。
这是得工作方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
3.5 优点
- 用户只需要关心所需要的产品对应的工厂,无须关心创建细节。
- 基于工厂角色和产品角色的多态性设计是工厂模式的关键。
- 向系统添加新产品时,无须修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,而只需要添加一个具体工厂和具体产品就可以了。完全符合“开闭原则”。
3.6 缺点
- 系统类的个数将成对增加,在一定程度上增加系统的复杂度。有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 引入抽象层,增加系统的抽象性和理解难度。
3.7 适用环境
- 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;
- 一个类通过其子类来指定创建哪些对象:利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将会覆盖父类对象,从而使得系统更容易扩展。
- 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
4、抽象工厂模式
4.1 定义
在工厂模式中具体工厂负责生产具体的产品,每一个具体工厂对应一个具体产品,一个具体工厂只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂提供多个产品对象,而不是单一的产品对象。
- 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机构成一个产品等级结构。抽象电视机是父类,而具体品牌电视机是其子类。
- 产品族:在抽象工厂模式中,产品族是同一个工厂生产的,位于不同产品等级中的一组产品,如海尔电气工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。
工厂模式针对是一个产品等级结构,抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
抽象工厂模式:提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式又称为Kit模式。
需要满足的条件:
- 系统中有对各产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
- 系统一次只可能消费某一族产品,即同族产品一起使用。
4.2 模式结构
- 抽象产品:定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
- 抽象工厂:提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
- 具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。

4.3 C++代码
#include <iostream>
#include <string>
using namespace std;
//抽象产品-产品等级A
class AbstractProductA {
public:
virtual void use() = 0;
};
//具体产品-产品等级A-产品族1
class ProductA1:public AbstractProductA
{
public:
void use() {
cout << "use Product A1"<<endl;
}
};
//具体产品-产品等级A-产品族2
class ProductA2:public AbstractProductA
{
public:
void use() {
cout << "use Product A2" << endl;
}
};
//抽象产品-产品等级B
class AbstractProductB {
public:
virtual void eat() = 0;
};
//具体产品-产品等级B-产品族1
class ProductB1 :public AbstractProductB
{
public:
void eat() {
cout << "eat Product B1" << endl;
}
};
//具体产品-产品等级B-产品族2
class ProductB2 :public AbstractProductB
{
public:
void eat() {
cout << "eat Product B2" << endl;
}
};
//抽象工厂
class AbstractFactory
{
public:
virtual AbstractProductA* createProductA() = 0;
virtual AbstractProductB* createProductB() = 0;
};
//具体工厂
class ConcreteFactory1:public AbstractFactory
{
public:
AbstractProductA* createProductA()
{
return new ProductA1();
}
AbstractProductB* createProductB()
{
return new ProductB1();
}
};
//具体工厂
class ConcreteFactory2 :public AbstractFactory
{
public:
AbstractProductA* createProductA()
{
return new ProductA2();
}
AbstractProductB* createProductB()
{
return new ProductB2();
}
};
int main()
{
AbstractFactory *cf1=new ConcreteFactory1();
AbstractProductA *pa1 = cf1->createProductA();
AbstractProductB *pb1 = cf1->createProductB();
pa1->use();
pb1->eat();
AbstractFactory *cf2 = new ConcreteFactory2();
AbstractProductA *pa2 = cf2->createProductA();
AbstractProductB *pb2 = cf2->createProductB();
pa2->use();
pb2->eat();
delete cf1, cf2;
delete pa1, pb1, pa2, pb2;
return 0;
}
4.4 优点
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要直到什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂实现了抽象中定义的那些接口,因此只需要改变具体工厂的实例,就可以在某种程序上改变整个软件系统的行为。实现了高内聚低耦合的设计目的。
- 能保证客户端始终只使用同一个产品族的对象。
- 增加新的具体工厂和产品族很方便,无需修改已有的系统,符合“开闭原则”。
4.5 缺点
- 添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,带来极大的不便
- 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦):
(1)增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
(2)增加产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。
4.6 适用环境
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
- 系统中有多于一个的产品族,而每次只使用某一产品族。
- 属于某一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
- 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
5、建造者模式
5.1 定义
无论是在现实世界还是软件系统,都存在一些复杂的对象,它们拥有多个足证部分,如汽车,它包括车轮、方向盘、发动机等各种部件。而对于大度哦书用户而言,无需知道这些部件的装配细节,也几乎不会使用单独某个部件,而是使用一辆完成的汽车。
建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。
在软件开发中,也存在大量类似汽车一样的复杂对象,他们拥有一系列成员属性,这些成员属性中有些是引用类型的成员对象。而且这些复杂对象中,还可能存在一些限制条件,如某些属性没有赋值则复杂对象不能作为一个完整的产品使用;有些属性的赋值必须按照某个顺序,一些属性没有赋值之前另外一个属性可能无法复赋值等。
建造者模式:指将一个复杂对象的构造和它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式称为建造者模式。它是将一个复杂对象分解为多个简单的对象,然偶一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
5.2 模式结构
- 抽象建造者:它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的复杂方法 getResult()。
- 具体建造者:实现抽象建造者的接口,完成复杂产品的各个部件的具体创建方法。
- 指挥者:它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
- 产品角色:它是包含多个组成部件的复杂对象,由具体建造则来创建其各个部件。

5.3 C++代码
#include <iostream>
#include <string>
using namespace std;
//产品角色:包含多个组成部件的复杂对象
class Product
{
private:
string partA;
string partB;
string partC;
public:
void setPartA(string partA)
{
this->partA = partA;
}
void setPartB(string partB)
{
this->partB = partB;
}
void setPartC(string partC)
{
this->partC = partC;
}
void show() {
//显示产品特性
cout << partA << endl << partB <<endl<< partC << endl;
}
};
//抽象建造者:包含创建产品各个子部件的抽象方法
class AbstractBuilder
{
protected:
Product *product;
public:
virtual void buildPartA() = 0;
virtual void buildPartB() = 0;
virtual void buildPartC() = 0;
AbstractBuilder() { product = new Product(); }
~AbstractBuilder() { delete product; }
Product* getResult()
{
return product;
}
};
//具体建造者:实现了抽象建造者的接口
class ConcreteBuilder:public AbstractBuilder
{
public:
void buildPartA()
{
product->setPartA("建造 PartA");
}
void buildPartB()
{
product->setPartB("建造 PartB");
}
void buildPartC()
{
product->setPartC("建造 PartC");
}
};
//指挥者:调用建造者中的方法完成对复杂对象的创建
class Director
{
private:
AbstractBuilder *builder;
public:
Director(AbstractBuilder *builder)
{
this->builder = builder;
}
Product* construct()
{
builder->buildPartA();
builder->buildPartB();
builder->buildPartC();
return builder->getResult();
}
};
class Client
{
public:
static void main()
{
AbstractBuilder *builder = new ConcreteBuilder();
Director * director = new Director(builder);
Product *product = director->construct();
product->show();
delete builder, director;
}
};
int main()
{
Client::main();
return 0;
}
5.4 优点
- 客户端不必知道产品内部组成细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 每一个具体建造者都相对独立,因此可以很方便的替换具体建造者或者增加新的具体建造者。用户使用不同的具体建造者即可得到不同的产品对象。
- 可以更加精细的控制产品的创建过程。
- 增加新的具体建造者无需修改原有的类库代码。符合“开闭原则”。
5.5 缺点
- 建造者模式所创建的产品一般具有较多的共同点,组成部分相似,如果产品差异性很大,则不适合使用。
- 如果产品内部变化复杂,可能回导致需要定义很多具体建造者来实现这种变化,导致系统变的很庞大。
5.6 适用环境
- 需要需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
- 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
- 对象的创建过程独立于创建该对象的类。在建造者模式中引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类中。
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
5.7 简化
- 省略抽象建造者角色:如果系统中只需要一个具体建造者的话,可以省略掉抽象建造者。
- 省略指挥者角色:在具体建造者只有一个的情况下,如果抽象建造者角色已经被省略掉,那么还可以省略指挥者角色,让Builder角色扮演指挥者与建造者双重角色。
6、单例模式
6.1 定义
对于系统中的某些类来说,只有一个实例很重要,例如,译者系统中可以存在多个打印任务,但是又能有一个正在工作的任务。
让类自身保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。
**单例模式:**确保某一个类只有一个实例,而且自行实例化想整个系统提供这个实例,这个类成为单例类,它提供全局访问的方法。
单例模式的要点有三个:
- 某个类只能有一个实例
- 它必须自行创建这个实例
- 它必须自行向整个系统提供这个实例
6.2 模式结构
- 单例类:包含一个实例且能自行创建这个实例的类
- 访问类:使用单例的类

6.3 C++代码
#include <iostream>
#include <string>
using namespace std;
//懒汉式单例
/*
该模式的特点是类加载的时候没有生成单例,只有当第一次调用getInstance
方法时采取创建这个单例
*/
class LazySingleton
{
private:
static LazySingleton* instance;
LazySingleton() {}//private避免类在外部被实例化
public:
static LazySingleton* getInstance()
{
if (instance == NULL)
{
instance = new LazySingleton();
}
return instance;
}
};
//饿汉式单例
/*
该模式的特点是类一旦加载就创建一个单例,
保证在调用getInstance方法之前单例就已经存在了
*/
class HungrySingleton
{
private:
static HungrySingleton *instance;
HungrySingleton() {}
public:
static HungrySingleton* getInstance()
{
return instance;
}
};
HungrySingleton *HungrySingleton ::instance= new HungrySingleton();
class Client
{
protected:
static LazySingleton* ls;
static HungrySingleton* hs;
public:
static void main()
{
ls=LazySingleton::getInstance();
hs=HungrySingleton::getInstance();
}
};
6.4 优点
- 提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它,并为设计及开发团队提供了共享的概念。
- 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
- 允许可变数目的实例。我们可以基于单例模式进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例。
6.5 缺点
- 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
- 单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致对象状态的丢失。
6.6 适用环境
- 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。
- 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。
- 当某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
5.6 扩展为多例模式

本文详细介绍了创建型设计模式,包括简单工厂模式、工厂模式、抽象工厂模式、建造者模式和单例模式。这些模式分别适用于不同的场景,如简单工厂模式适合创建对象较少且类型固定的系统,工厂模式通过工厂子类实现对象创建的多态性,抽象工厂模式则处理多个产品族的创建。建造者模式用于构建复杂对象,而单例模式确保一个类只有一个实例。每种模式都有其优缺点,需要根据实际需求选择合适的模式。
&spm=1001.2101.3001.5002&articleId=93048951&d=1&t=3&u=e8057f3545eb4a55b2ca573243b6b626)
562

被折叠的 条评论
为什么被折叠?



