Contents

设计模式总结一

说起可复用的面向对象软件,我又想起了一句"至理名言”,万物基于MIUI

设计模式就是一套基于面向对象而总结出来的设计范式,它能使代码符合高内聚低耦合的目标。

设计模式的分类:

/images/design_pattern_1.png

1.1 单例模式 (Singleton)

特点: 保证一个类只有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量来控制对象的访问,但它不能防止你实例化多个对象。一个最好的方法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。

应用场景

  • a. 当类只能有一个实例而且可以从一个众所周知的访问点访问它时。

  • b.当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

UML图

/images/design_pattern_2.png

实现

 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
37
38
39
40
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;
class Singleton
{
public:
	static Singleton* GetInstance()
	{
		if(instance == nullptr)
		{
			{
				std::lock_guard<std::mutex> lck(mtx);
				if(instance == nullptr)
				{
					instance = new Singleton();
				}
			}
			return instance;
		}
	}
private:
	Singleton() = default;
private:
	static Singleton *instance;
};

Singleton *Singleton::instance = nullptr;

int main()
{
	Singleton *p1 = Singleton::GetInstance();
	Singleton *p2 = Singleton::GetInstance();
	if(p1 == p2)
	{
	  std::cout << "Same" << std::endl;
	}
  delete p1;
}

优点

  • a.对唯一实例受控访问
  • b.缩小命名空间
  • c.允许对操作和表示的精细化
  • d.允许可变数目的实例
  • e.比静态类操作更灵活

缺点:无

1.2 工厂方法模式(Factory Method)

特点

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

应用场景

  • a.当一个类不知道它所必须创建的对象的类的时候
  • b.当一个类希望由它的子类来指定它所创建的对象的时候
  • c.当类将创建对象的职责委托给多个帮助子类中的某一个,并且希望将哪一个帮助子类是代理者这一信息局部化的时候

UML图

/images/design_pattern_3.png

实现

 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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <string>

//  product interface
class Product
{
public:
    virtual std::string GetName() = 0;
};

// factory interface
class Creator
{
public:
    virtual Product* FactoryMethod() = 0;
};

class ProductA:public Product
{
public:
    std::string GetName() override
    {
        return "Product A";
    }
};
class ProductB:public Product
{
public:
    std::string GetName() override
    {
        return "Product B";
    }
};

class CreatorA:public Creator
{
public:
    Product* FactoryMethod() override
    {
        return new ProductA();
    }
};

class CreatorB:public Creator
{
public:
    Product* FactoryMethod() override
    {
        return new ProductB();
    }
};
int main()
{

	Creator *factory = new CreatorA();
	Product *product = factory->FactoryMethod();
	std::cout << "product name: " << product->GetName() << std::endl;
	delete factory;

	factory = new CreatorB();
	product = factory->FactoryMethod();
	std::cout << "product name: " << product->GetName() << std::endl;

	delete factory;
	delete produtc;
	return 0;
}

优点

  • a.去除了客户端与具体产品的依赖
  • b.为子类提供挂钩
  • c.连接平行的类层次

缺点

具体产品创建依赖于具体工厂

1.3 抽象工厂模式(Abstract Factory)

特点

提供一个创建一系列相关或者相互依赖对象的接口,而无需指定具体的类。

应用场景

  • a.一个系统要独立于它的产品创建、组合和表示时
  • b.一个系统要由多个产品系列中的一个来配置时
  • c.当要强调一系列相关的产品对象的设计以便进行联合使用时
  • d.当提供一个产品类库,而只想显示它们的接口而不是实现时

UML图

/images/design_pattern_4.png

实现

  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
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
#include <iostream>
#include <string>

class AbstractProductA;
class AbstractProductB;
class AbstractFactory
{
public:
    virtual AbstractProductA* CreateProductA() = 0;
    virtual AbstractProductB* CreateProductB() = 0;
};

class AbstractProductA
{
public:
    virtual std::string GetFirstName() = 0;
};

class AbstractProductB
{
public:
    virtual std::string GetLastName() = 0;
};

class ProductA1: public AbstractProductA
{
public:
    std::string GetFirstName() override
    {
        return "ProductA first name: 1";
    }
};
class ProductA2:public AbstractProductA
{
public:
    std::string GetFirstName() override
    {
        return "ProductA first name: 2";
    }
};

class ProductB1:public AbstractProductB
{
public:
    std::string GetLastName() override
    {
        return "ProdcuctB last name: 1";
    }
};

class ProductB2:public AbstractProductB
{
public:
    std::string GetLastName() override
    {
        return "ProductB last name: 2";
    }
};


class ConcreteFactory1:public AbstractFactory
{
public:
    AbstractProductA* CreateProductA() override
    {
        return new ProductA1;
    }
    AbstractProductB* CreateProductB() override
    {
        return new ProductB1();
    }
								
};
class ConcreteFactory2:public AbstractFactory
{
public:
    AbstractProductA* CreateProductA() override
    {
        return new ProductA2;
    }
    AbstractProductB* CreateProductB() override
    {
        return new ProductB2();
    }

};
int main()
{
    AbstractFactory *factory = new ConcreteFactory1();
    AbstractProductA *pa = factory->CreateProductA();
    AbstractProductB *pb = factory->CreateProductB();
    std::cout << pa->GetFirstName() << std::endl;
    std::cout << pb->GetLastName() << std::endl;

    delete factory;
    delete pa;
    delete pb;
    
    factory = new ConcreteFactory2();
    pa = factory->CreateProductA();
    pb = factory->CreateProductB();
    std::cout << pa->GetFirstName() << std::endl;
    std::cout << pb->GetLastName() << std::endl;
    
    delete factory;
    delete pa;
    delete pb;
    
    return 0;
}

优点

  • a.分离了具体的类
  • b.使得易于交换产品系列
  • c.有利于产品的一致性

缺点

难以支持新种类的产品

1.4 建造者模式(Builder)

特点

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。如果我们使用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。

应用场景

  • a.当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时
  • b.当构造过程必须允许被构造的对象有不同的表示时

UML图

/images/design_pattern_5.png

实现

  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
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include <string>

class Product;
class Builder
{
public:
    virtual void BuildPartA() = 0;
    virtual void BuildPartB() = 0;
    virtual Product* GetResult() = 0;
};

class Product
{
public:
    void Add(std::string part)
    {
        name_ += part;
    }
    std::string Show()
    {
        return name_;
    }
private:
    std::string name_ = "";
};

class ConcreteBuilder1:public Builder
{
public:
    ConcreteBuilder1()
    {
        product = new Product();
    }
    ~ConcreteBuilder1()
    {
        delete product;
    }
    void BuildPartA() override
    {
        product->Add("Part A ");
    }
    void BuildPartB() override
    {
        product->Add("Part B ");
    }
    Product* GetResult() override
    {
        return new Product(*product);
    }

private:
    Product *product;
};

class ConcreteBuilder2:public Builder
{
public:
    ConcreteBuilder2()
    {
        product = new Product();
    }
    ~ConcreteBuilder2()
    {
        delete product;
    }
    void BuildPartA() override
    {
        product->Add("Part 1 ");
    }
    void BuildPartB() override
    {
        product->Add("Part 2 ");
    }
    Product* GetResult() override
    {
        return new Product(*product);
    }

private:
    Product *product;
};

class Director
{
public:
    void Construct(Builder *builder)
    {
        builder->BuildPartA();
        builder->BuildPartB();
    }
};
int main()
{
    Director *d = new Director();
    Builder *b1 = new ConcreteBuilder1();
    Builder *b2 = new ConcreteBuilder2();
    Product *p = nullptr;

    d->Construct(b1);
    p = b1->GetResult();
    std::cout << p->Show() << std::endl;
    delete p;

    d->Construct(b2);
    p = b2->GetResult();
    std::cout << p->Show() << std::endl;
    delete p;

    delete d;
    delete b1;
    delete b2;
}

优点

  • a.可以改变产品的内部表示
  • b.将构造代码和表示代码分开
  • c.可以对构造过程进行更精细的控制

缺点

暂无

1.5 原型模式(Prototype)

特点

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

应用场景

  • a.当一个系统应该独立于它的产品创建、构成和表示时
  • b.当要实例化的实例在运行时刻指定时
  • c.为了避免创建一个与产品类层次平行的工厂类层次时
  • d.当一个类的实例只能有几个不同状态组合中的一种时

UML图

/images/design_pattern_6.png

实现

 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
class Prototype
{
public:
    Prototype(std::string id)
    {
        this->id = id;
    };
    std::string id;
    virtual Prototype* Clone() = 0;
};

class ConcretePrototype: public Prototype
{
public:
    ConcretePrototype(std::string id)
        :Prototype(id)
    {
    }
    Prototype* Clone() override
    {
        return new ConcretePrototype(*this);
    }
};
int main()
{
    ConcretePrototype *p1 = new ConcretePrototype("1");
    ConcretePrototype *p2 = (ConcretePrototype*)(p1->Clone());
    std::cout << "Cloned: " << p2->id << std::endl;

    delete p1;
    delete p2;
    return 0;
}

优点

  • a.运行时刻增加和删除产品
  • b.改变值以指定新对象
  • c.改变结构以指定新对象
  • d.减少子类的构造
  • e.用类动态配置应用

缺点

每一个Prototype子类都必须实现Clone接口,这对于有的类来说比较困难