编程拾遗系列设计模式-创建型模式
Posted 前端小板凳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编程拾遗系列设计模式-创建型模式相关的知识,希望对你有一定的参考价值。
为什么开启设计模式系列
在业务压力下,仓库的代码量是快速增长的。最近在思考如何能让代码有灵活性和扩展性。随着产品的迭代,一部分业务逻辑需要重新实现,那一种良好的设计是否能在重构代码中帮助我们呢?答案是确定的。开启这个系列主要有这两方面的原因:
在翻译业务的时候更高效和优雅
通过对模式的学习能加强思考
设计模式是解决一类问题的通用的方案,希望通过对设计模式的学习能完善解决问题的能力,本系列会结合《设计模式-可复用面向对象软件的基础》来对设计模式进行比较全面的梳理。
创建型模式
创建型模式通过对实例化过程进行抽象,隐藏了底层的具体实现,从而实现更多的灵活性。创建型模式有以下几种:
Abstract Factory(抽象工厂)
Builder(生成器)
Factory Method(工厂方法)
Prototype(原型)
Singleton(单例)
本文会结合一个创建迷宫的示例来介绍以上几种设计模式.通常实现一个迷宫会定义以下基类:
// 方向枚举
enumDirection{ North, South, East, West};
classMapSite{
public: virtualvoidEnter() = 0;
}
// 房间
classRoom: publicMapSite{
public:
Room(int roomNo);
MapSite* GetSide(Direction) const;
void SetSide(Direction, MapSite*)
private:
MapSite* _sides[4];
int _roomNumber;
}
// 墙
classWall: publicMapSite{
public:
Wall();
virtual void Enter();
}
// 门
classDoor: publicMapSite{
public:
Door(Room* = 0, Room* = 0);
virtual void Enter();
Room* OthersSideFrom(Room*);
private:
Room* _room1;
Room* _room2;
bool _isOpen;
}
// 迷宫类
classMaze{
public:
Maze();
void AddRoom(Room*);
Room* RoomNo(int) const;
private:
}
// 一个可能的迷宫生成代码
Maze* MazeGame::CreateMaze() {
Maze* aMaze = newMaze();
Room* r1 = newRoom();
Room* r2 = newRoom();
Door* theDoor = newDoor(r1,r2);
aMaze->AddRoom(r1);
aMaze->AddRoom(r2);
r1.SetSide(North, newWall);
r2.SetSide(North, newWall);
// 省略很多的SetSide操作
return aMaze
}
通过上面的代码实现的迷宫中硬编码了实现迷宫的行为,不利于扩展,下面通过对创建型设计模式的学习来优化上述代码的问题。
Abstract Factory(抽象工厂)
抽象工厂提供一个创建一系列相关或相互依赖对象的接口而无需指定他们具体的类。
结构
AbstractFactory
声明一个创建抽象产品对象的操作接口ConcreteFactory
实现创建具体产品对象的操作AbstractProduct
为一类产品对象声明接口ConcreteProduct
定义一个将被相应具体工厂创建的产品对象,实现AbstractProduct接口Client
仅使用由AbstractFactory和AbstractProduct类声明的接口
适用性
抽象工厂通过将具体的对象创建延迟到ConcreteFactory中,能提供丰富的灵活性,适用于以下场景:
一个系统要独立于它的产品的创建,组合和表示时
一个系统要由多个产品系列中的一个来配置时
需要对一系列相关产品对象设计进行联合使用时
对外提供产品类库,提供统一的接口
代码示例
下面的代码使用Abstract Factory模式来创建一个迷宫,相对于直接在代码中硬编码创建迷宫的方式,通过传递ConcreteFactory来完成具体迷宫的创建.
Maze*MazeGame::CreateMaze(MazeFactory& factory){
Maze* aMaze = factory.MakeMaze();
Room* r1 = factory.MakeRoom(1);
Room* r2 = factory.MakeRoom(2);
Door* aDoor = factory.MakeDoor(r1, r2);
aMaze->AddRoom(r1);
aMaze->AddRoom(r2);
r1.SetSide(North, factory.MakeWall())
r2.SetSide(North, factory.MakeWall());
// 省略很多的SetSide操作
return aMaze;
}
通过传递ConcreteFactory,上面的代码将创建逻辑都封装在具体工厂中,这样通过传递不同的工厂就能完成不同类型对象的创建。
Builder(生成器)
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。Builder模式能更好的封装产品的内部表示。
结构
Builder 为创建一个Product对象的各个部件指定抽象接口
ConcreteBuilder
实现Builder的接口来完成对象的创建 定义并明确它所创建的表示 提供一个检索产品的接口Director 构建一个使用Builder的接口对象
Product
被构造的复杂对象
抽象的Builder类为Director要创建的对象定义操作。ConcreteBuilder实现Builder定义的方法
适用性
通过生成器可以把复杂的对象创建过程隐藏,通过不同的Builder来完成系统的创建, 适用于以下场景:
当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时
当构造过程必须允许被构造的对象有不同的表示时
示例代码
class MazeBuilder {
public:
virtualvoid BuildMaze() {};
virtual void BuildRoom(int room)
{};
virtual void BuildDoor(int roomFrom
, int roomTo) {}
virtual Maze* GetMaze() { return 0 };
protected:
MazeBuilder();
}
// 在具体调用的时候 可以传递一个实现了抽象类builder的ConcreteBuilder
Maze* MazeGame::CreateMaze(MazeBuilder&
builder) {
builder.BuildMaze();
builder.BuildRoom(1);
builder.BuildRoom(2);
builder.BuildDoor(1,2);
return builder.GetMaze();
}
对比抽象工厂,Builder模式封装了创建过程的细节,通过不同的builder实现可以创建出不同的对象。
Factory Method(工厂方法)
工厂方法定义一个用于创建对象的接口,让子类来实现对应的接口来创建对象。
结构
Product 定义工厂方法所创建对象的接口(抽象产品)
ConcreateProduct
实现Product的接口(具体产品)Creator
声明工厂方法(抽象工厂)ConcreteCreator
实现工厂方法,返回ConcreateProduct实例
工厂方法依赖它的子类来实现工厂方法来完成对象的创建。
适用性
工厂方法适用于以下场景:
父类不知道它需要创建的对象的类的时候
当一个类希望它的子类来指定创建对象的时候
示例代码
class MazeGame {
public:
Maze* CreateMaze();
// factory method;
virtual Maze* MakeMaze() const { return new Maze(); };
virtual Room* MakeRoom(int n ) const { return new Room(n); };
virtual Wall* MakeWall() const { return new Wall; };
virtual Door* MakeDoor(Room* r1,
Room* r2) const {
return new Door(r1, r2); };
}
Maze* MazeGame::CreateMaze() {
Maze* aMaze = new Maze();
Room* r1 = new Room();
Room& r2 = new Room();
Door* theDoor = new Door(r1,r2);
aMaze->AddRoom(r1);
aMaze->AddRoom(r2);
r1.SetSide(North, new Wall);
r2.SetSide(North, new Wall);
// 省略很多的SetSide操作
return aMaze
}
// 子类实现工厂方法来完成对象的创建
class BombedMazeGame : public MazeGame {
public:
BombedMazeGame()
virtual Room* MakeRoom(int n) const
{
return new RoomWithBomb(n);
};
}
PROTOTYPE(原型)
原型模式通过原型实例指定创建对象的种类,通过拷贝原型来创建新的对象
结构
Prototype
声明一个克隆自身的接口ConcretePrototype
实现一个克隆自身的操作Client
让一个原型克隆自身从而创建一个新的对象
适用性
原型模式适用于以下场景:
实例化的类需要在运行时刻指定
类的实例状态是相似的,通过原型的克隆能减少类的创建
示例代码
class MazePrototypeFactory : public MazeFactory {
public :
MazePrototypeFactory(Maze* , Wall*, Room*, Door*);
virtual Maze* MakeMaze() const;
virtual Room* MakeRoom(int) const;
virtual Wall* MakeWall() const;
virtual Door* MakeDoor(Room*, Room*) const;
private:
Maze* _prototypeMaze;
Room* _prototypeRoom;
Wall* _prototypeWall;
Door* _prototypeDoor;
}
MazePrototypeFactory::MazePrototypeFactory (
Maze* m, Wall* w, Room* r,Door* d
) {
_prototypeMaze = m;
_prototypeRoom = r;
_prototypeWall = w;
_prototypeDoor = d;
}
Wall* MazePrototypeFactory::MakeWall() const {
return _prototypeWall->Clone();
}
MazeGame game;
// 需要初始化传入的实例支持clone操作,可以通过传递不同的实例完成不同的对象创建
MazePrototypeFactory simpleMazeFactory(
new Maze,new Wall,new Room, new Door);
Maze* maze = game.CreateMaze(
simpleMazeFactory)
SINGLETON(单例)
保证一个类仅有一个实例,并提供一个访问他的全局访问点
结构
Singleton 定义一个Instance操作,允许客户访问它的唯一实例
适用性
单例模式适用于以下场景:
唯一的实例需要全局访问时
示例代码
class Singleton {
public:
static Singleton* Instance();
protected:
Singleton();
private:
static Singleton* _instance;
}
Singleton* Singleton::_instance = 0;
// 对成员初始化未空,第一次访问的时候创建成员,再次访问直接范返回成员
Singleton* Singleton::Instance() {
if(_instance == 0) {
_instance = new Singleton();
}
return _instance;
}
在单例模式中,想要实现动态的确定单例的类型方式,可以通过维护单例注册表的方式来实现。
以上是关于编程拾遗系列设计模式-创建型模式的主要内容,如果未能解决你的问题,请参考以下文章