分析qemu开源代码有一段时间了,时常惊叹于qemu中某些功能实现的灵活巧妙,qemu中对于I/O的处理方法、qemu设备模型、qemu中的通知链等。阅读qemu代码时常想起已经忘记的差不多的设计模式,在学校时曾经阅读过设计模式方面的书籍,当时理解的就相当的抽象,加上毕业后的工作中编写代码的机会很少,以至于大部分都已经忘得差不多。

  对于开源软件的分析,再一次感受到设计模式在一款优秀软件中的至关重要的作用,希望这几天抽时间再次翻一翻设计模式相关的书籍,将重要的知识点和理解记录下来,希望能够对软件设计方法能够有更加深层次的理解。下面首先是针对 对象创建型设计模式的总结。

  在代码中直接实例化具体类,硬编码具体类,会使程序的可扩展性变的很差。创建型设计模式抽象了具体类的实例化过程,可以在客户实现代码中移除对具体类的引用,提高了程序的可扩展性,这些模式通常具有以下特点:1、将关于该系统使用那些具体类的信息封装起来。2、隐藏了这些类的实例是如何被创建和放在一起的。

  在介绍创建型设计模式之前,先引用《设计模式-可复用面向对象软件的基础》中的一个例子:迷宫游戏的例子。

1. 一个迷宫游戏的例子

  迷宫游戏中需要有一个迷宫地图,迷宫地图由房间,门,墙这三种元素组成。因此定义迷宫元素抽象类MapSite,并且以这个抽象类为父类定义三个具体类:房间、门、墙,另外定义迷宫地图类Maze和迷宫游戏类型MazeGame。这一个抽象类和四个具体类是迷宫游戏程序中创建迷宫对象会用到的类型, MazeGame类型用于创建一个迷宫游戏。

/* 迷宫元素抽象类 */ 
class MapSite {
public:
       virtual void Enter() = 0;      
};

/* 迷宫房间类型 */ 
class Room : public MapSite {
public:
       Room(int roomNo);
       MapSite* GetSide(Direction) const;
       void SetSide(Direction, MapSite*);
       
       virtual void Enter();
private:
        MapSite* _sides[4];
        int _roomNumber;
};

/* 迷宫墙类型 */ 
class Wall : public MapSite {
public:
       Wall();
       
       virtual void enter();
};

/* 迷宫门类型 */ 
class Door : public MapSite {
public:
       Door(Room* = 0, Room* = 0);
       
       virtual void Enter();
       Room* OtherSideFrom(Room*);
       
private:
        Room* _room1;
        Room* _room2;
        bool _isOpen;         
};

/* 迷宫类型 */
class Maze {
public:
       Maze();
       
       void AddRoom(Room*);
       Room* RoomNo(int) const;
       
private:
        //...     
};

/* 迷宫游戏类 */
class MazeGame {
public:
       Maze* CreateMaze();
       //...
private:
        //...    
} 

  创建一个迷宫游戏首先从创建一些对象开始,包括最重要的迷宫地图对象。MazeGame中定义了public方法 CreateMaze()用来创建迷宫地图,这个函数可以通过直接引用Room、Door、Wall具体类,创建多个Room对象、Door对象和Wall对象来组装一个迷宫地图,通过这种方法创建一个包括两个房间的迷宫地图的CreateMaze实现如下:

Maze* MazeGame::CreateMaze() {
    Maze* aMaze = new Maze();
    Room* r1 = new Room(1);
    Room* r2 = new Room(2);
    Door* theDoor = new Door(r1, r2);
    
    aMaze->AddRoom(r1);
    aMaze->AddRoom(r2);
    
    r1->SetSide(North, new Wall);
    r1->SetSide(East, the Door);
    r1->SetSide(South, new Wall);
    r1->SetSide(West, new Wall);
    
    r2->SetSide(North, new Wall);
    r2->SetSide(East, new Wall);
    r2->SetSide(South, new Wall);
    r2->SetSide(West, the Door);
}

  上面CreateMaze创建一个迷宫地图的方式存在两个问题:

  1、创建迷宫地图中的元素时直接引用了具体类。如果我们同样想创建一个迷宫地图结构和上面一样,但是带有魔法效果的迷宫,此时需要实例化带有魔法效果的房子和门等,如果不通过派生新的MazeGame类以重载creatGame函数来创建带有魔法效果的迷宫,那么只有修改现有类的CreateGame函数的实现。在这种情况下,我们可以复用创建迷宫结构的代码,通过类参数来创建拥有相同的迷宫结构但不同类型迷宫元素的迷宫地图,抽象工厂可以帮助我们实现这一点。

  2、创建的迷宫的结构是硬编码的。如果我们想创建包含5个房子的迷宫地图(使用相同类型元素创建不同结构的产品),和上面的问题一样,要么通过派生子类重载创建产品的函数并使用派生类创建新的对象,要么修改CreateGame的函数。

  常用的创建型模式主要有:抽象工厂工厂方法生成器原型,另外抽象工厂通常实现为单件模式,后面依次使用这几种设计模式解决CreateGame创建对象的问题。

转载于:https://www.cnblogs.com/VincentXu/p/3337880.html

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐