Design patterns---Creational Patterns

Creational design patterns abstract the instantiation process.They help make a system independent of how its objects are created,composed,and represented.A class creational pattern uses inheritance to vary the class that’s instantiated,whereas an object creational will delegate instantiation to another object.
Creational patterns become important as system evolve to depend more on object composition than class inheritance.As that happens,emphasis shifts away from hard-coding a fixed set of behaviors toward defining a smaller set of fundamental behaviors that can be composed into any number of more complex ones.Thus creating objects with particular behaviors requires more than simply instantiating a class.
I.Abstract Factory
Intent:Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
Applicability:Use tge Abstract Factory pattern when
*a system should be independent of how its product are created,composed,and represented.
*a system should be configured with one of multiple families of products.
*a family of related product objects is designed to be used together,and you need to enforce this constraint.
Structure:
在这里插入图片描述Benefits:
*It isolates concrete classes.
*It makes exchanging product families easy.
*It promotes consistency among products.
Liabilities:
Supporting new kinds of products is difficult.

Implementation:
*Factories as singletons.
*Creating the products
*Defining extensible factories.

Sample Code: //C++,This is not a program but a sample

enum Direction{North,South,East,West};
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 Spell{
   public :bool exist;
};
class EnchantedRoom:public Room{
    public:
    EnchantedRoom(int roomNo,Spell*);
    private:
    Spell* sp;
};
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 DoorNeedingSpell :public Door{
   public: 
   DoorNeedingSpell(Room *r1,Room* r2);
   bool hasSpell();
};
class Maze{
    public :
    Maze();
    void AddRoom(Room*);
    Room* RoomNo(int) const;
    private:
    vector<Room*> rooms;
};
class MazeGame{
    Maze* CreateMaze(MazeFactory& factory);
};
//以下为工厂设计模式:
 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());
r1->SetSide(East,aDoor);
r1->SetSide(South,factory.MakeWall());
r1->SetSide(West,factory.MakeWall());
r2->SetSide(North,factory.MakeWall());
r2->SetSide(East,factory.MakeWall());
r2->SetSide(South,factory.MakeWall());
r2->SetSide(West,aDoor);

return aMaze;
    }
class MazeFactory{
    public :
    MazeFactory();
    virtual Maze* MakeMaze() const
    {
        return new Maze;
    }
      virtual Wall* MakeWall() const
    {
        return new Wall;
    }
      virtual Room* MakeRoom(int n) const
    {
        return new Room(n);
    }
      virtual Door* MakeDoor(Room* r1,Room *r2) const
    {
        return new Door(r1,r2);
    }
};
class EnchantedMazeFactory:public MazeFactory{
    public :
    EnchantedMazeFactory();
    virtual Room* MakeRoom(int n) const{
        return new EnchantedRoom(n,CastSpell());
    }
    virtual Door* MakeDoor(Room* r1,Room *r2) const
    {
        return new DoorNeedingSpell(r1,r2);
    }
    protected:
    Spell* CastSpell() const;
    };

II.Builder
Intent:Separate the construction of a complex object from its representation so that the same construction process can create different representations.

Applicability:Use the Builder pattern when
*The algorithm for creating a complex object should be independent of the parts that make up the object and how they’re assembled.
*The construction process must allow different representations for the object that’s constructed.

Structure:
在这里插入图片描述Collaborations:
在这里插入图片描述
Consequences:
*It lets you vary a product’s internal representation.
*It isolates code for construction and representation.
*It gives you finer control over the construction process.

Implementation:
*Assembly and construction interface.
*Why no abstract class for products?
*Empty methods as default in Builder.

Sample Code: //C++,This is not a program but a sample

 class MazeBuilder{
public:
   virtual void BuildMaze(){}
   virtual void BuildRoom(int room){}
   virtual void BuildDoor(int roomFrom,int roomTo){}

   virtual Maze* GetMaze(){return 0;}
   protected:
   MazeBuilder();
};
 Maze* MazeGame::Createmaze(MazeBuilder& builder)
{
  builder.BuildMaze();  
  builder.BuildRoom(1);
  builder.BuildRoom(2);
  builder.BuildDoor(1,2);
  return builder.GetMaze();
    }
class StandardMazeBuilder:public MazeBuilder{
    public :
    StandardMazeBuilder();

    virtual void BuildMaze();
    virtual void BuildRoom(int);
    virtual void BuildDoor(int,int);
    virtual Maze* GetMaze();
    private:
    Direction CommonWall(Room* r1,Room* r2){
        if(r1->Getside(East)==r2->Getside(West))
          return East;
        if(r1->Getside(North)==r2->Getside(South))
          return North;
        if(r1->Getside(West)==r2->Getside(East))
          return West;
        if(r1->Getside(South)==r2->Getside(North))
          return South;      
    }
    Maze* _currentMaze;
};
StandardMazeBuilder::StandardMazeBuilder(){
    _currentMaze=0;
}
void StandardMazeBuilder::BuildMaze(){
    _currentMaze=new Maze;
}
Maze* StandardMazeBuilder::GetMaze(){
    return _currentMaze;
}
void StandardMazeBuilder::BuildRoom(int n)
{
    if(!_currentMaze->RoomNo(n))
    {
        Room* room=new Room(n);
        _currentMaze->AddRoom(room);

        room->SetSide(North,new Wall);
        room->SetSide(South,new Wall);
        room->SetSide(East,new Wall);
        room->SetSide(West,new Wall);
    }
}
void StandardMazeBuilder::BuildDoor(int n1,int n2)
{
    Room* r1=_currentMaze->RoomNo(n1);
    Room* r2=_currentMaze->RoomNo(n2);
    Door* d=new Door(r1,r2);

    r1->SetSide(CommonWall(r1,r2),d);
    r2->SetSide(CommonWall(r2,r1),d);
}
 Abstract Factory is similar to Builder in that it too may construct complex objects.The primary difference is that the Builder pattern focuses on constructing  a complex object step by step.Abstract Factory's emphasis is on families of product objects(either simple or complex).Builder returns the product as a final step,but as far as the Abstract Factory pattern is concerned,the product gets returned immediately.

III Factory Method
Intent:Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.
Applicability:Use the Factory Method pattern when:
*a class can’t anticipate the class of objects it must create.
*a class wants its subclasses to specify the objects it creates.
*classed delegate responsibility to one of several helper subclasses,and you want to localize the knowledge of which helper subclass is the delegate.
Structure:
在这里插入图片描述
Consequences:
Factory methods eliminate the need to bind application-specific classes into your code.The code only deals with Product interface;therefore it can work with any user-defined ConcreteProduct classes.
A potential disadvantage of factory method is that clients might have to subclass the Creator class just to create a particular ConcreteProduct object.
*Provides hook for subclasses
*Connects parallel class hierarchies.
Implementation:
*Two major varieties
*Parameterized factory methods:

  class Creator{
    public :
     virtual Product* Create(ProductId);
};
Product* Creator::Create(ProductId id)
{

    if(id==MINE) return new MyProduct;
    if(id==YOURS) return new YourProduct;
    //repeat for remaining products...
    return 0;
}

*Language-specific variants and issues
Such as lazy initialization

class Creator{
    public :
    Product* GetProduct();
    protected:
    virtual Product* CreateProduct();
    private:
    Product* _product;
};
Product* Creator::GetProduct(){
    if(_product==0)
    _product=CreateProduct();
    return _product;
}

*Using templates to avoid subclassing

class Creator{
    public :
    virtual Product* CreateProduct()=0;
};
template<class TheProduct>
class StandardCreator:public Creator
{
    public:
    virtual Product* CreateProduct();
};
template<class TheProduct>
Product* StandardCreator<TheProduct>::CreateProduct(){
    return new TheProduct;
}

*Naming conventions

Sample Code://c++,This is not a program

class MazeGame{
    public:
    Maze* Createmaze();
    //factory methods:
    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=MakeMaze();
Room *r1=MakeRoom(1);
Room *r2=MakeRoom(2);
Door *aDoor=MakeDoor(r1,r2);
aMaze->AddRoom(r1);
aMaze->AddRoom(r2);
r1->SetSide(North,MakeWall());
r1->SetSide(East,aDoor);
r1->SetSide(South,MakeWall());
r1->SetSide(West,MakeWall());
r2->SetSide(North,MakeWall());
r2->SetSide(East,MakeWall());
r2->SetSide(South,MakeWall());
r2->SetSide(West,aDoor);

return aMaze;
    }
class BombedMazeGame:public MazeGame{
    public:
    BombedMazeGame();
    virtual Wall* MakeWall() const
    {return new BombedWall;}
    virtual Room* MakeRoom(int n)const
    {return new RoomWithABomb(n);}
}

Related Patterns:
Abstract Factory is often implemented with factory methods.
Factory methods are usually called within Template Methods.
Prototypes don’t require subclassing Creator.However ,they often require an Initialize operation on the Product class.

IV Prototype:
Intent: Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.
Applicability:
Use the Prototype pattern when a system should be independent of how its products are created,composed,and represented;and
*when the classes to instantiate are specified at run-time,for example,by dynamic loading;or
*to avoid building a class hierarchy of factories that parallels the class hierarchy of products;or
*when instances of a class can have one of only a few different combinations of state.It may be more convenient to install a corresponding number of prototypes and clone them rather than instantiating the class manually,each time with the appropriate state.
Structure:
在这里插入图片描述Consequences:
Prototype has many of the same consequences that Abstract Factory and Builder have:It hides the concrete product classes from the client,thereby reducing the number of names clients know about.Moreover,these patterns let a client work with application-specific classes without modification.
*Adding and removing products at run-time
*Specifying new objects by varying values.
*Specifying new objects by varying structure
*Reduced subclassing
*Configuring an application with classes dynamically

The main liability of the Prototype pattern is that each subclass of Prototype must implement the clone operation,which may be difficult.

Implementation:
*Using a prototype manager.
To keep a registry of available prototypes.
A prototype manager is an associative store that returns the prototype matching a given key.
*Implementing the Clone operation.
The hardest part of the Prototype pattern is implementing the clone operation correctly.
*Initializing clones.
Sample Code://C++,This is not a program

class Door:public MapSite{
  public :
  Door(Room* =0,Room* =0);
  Door();
  Door(const Door&);
  virtual void Enter();
  virtual void Initialize(Room*,Room*);
  virtual Door* Clone() const;
  Room* OtherSideFrom(Room*);
  private:
  Room* _room1;
  Room* _room2;
  bool _isopen;
};
Door::Door(const Door& other)
{
    _room1=other._room1;
    _room2=other._room2;
}
void Door::Initialize(Room* r1,Room* r2)
{
    _room1=r1;
    _room2=r2;
}
Door* Door::Clone()const{
    return new Door(*this);
}
class BombedWall:public Wall{
    public:
    BombedWall();
    BombedWall(const BombedWall&);
    virtual Wall* Clone()const;
    bool HasBomb();
    private:
    bool _bomb;
};
BombedWall::BombedWall(const BombedWall& other):Wall(other)
{
    _bomb=other._bomb;
}
Wall* BombedWall::Clone()const{
    return new BombedWall(*this);
}
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;
    _prototypeWall=w;
    _prototypeRoom=r;
    _prototypeDoor=d;
};
Wall* MazePrototypeFactory::MakeWall() const{
    return _prototypeWall->Clone();
}
Door* MazePrototypeFactory::MakeDoor(Room* r1,Room *r2)const{
    Door* door=_prototypeDoor->Clone();
    door->Initialize(r1,r2);
    return door;
}

//How to use?
MazeGame game;
MazePrototypeFactory simpleMazeFactory(new Maze,new Wall,new Room,new Door);
Maze* maze=game.Createmaze(simpleMazeFactory);

//Now you can change the type of maze easily with a different set of prototypes
MazePrototypeFactory bombedMazeFactory(new Maze,new BombedWall,new RoomWithABomb,new Door);

Related Patterns:
Prototype and Abstract Factory are competing patterns in some ways.They can also be used together,however.An Abstract Factory might store a set of prototypes from which to clone and return product objects.
Designs that make heavy use of the Composite and Decorator patterns often can benefit from Prototype as well.

V Singleton
Intent:Ensure a class only has one instance,and provide a global point of access to it.

Applicability:Use the singleton pattern when:
*there must be exactly one instance of a class,and it must be accessible to clients from a well-known access point.
*when the sole instance should be extensible by subclassing ,and clients should be able to use an extended instance without modifying their code.

Structure:
在这里插入图片描述
Consequences:
*Controlled access to sole instance.
*Reduced name space.
*Permits refinement of operations and representation .
*Permits a variable number of instances.
*More flexible than class operations.

Implementation
*Ensuring a unique 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;
}

It isn’t enough to define the singleton as a global or static object and then rely on automatic initialization.There are three reasons for this:
(a):We can’t guarantee that only one instance of a static object will ever be declared.
(b):We might not have enough information to instantiate every singleton at static initialization time. A singleton might require values that are computed later in the program’s execution.

*Subclassing the Singleton class.

Sample Code:

class MazeFactorySingle{
    public:
    static MazeFactorySingle* Instance();
    //other interface goes here
    protected:
    MazeFactorySingle();
    private:
    static MazeFactorySingle* _instance;
};
MazeFactorySingle* MazeFactorySingle::_instance=0;

MazeFactorySingle* MazeFactorySingle::Instance(){
    if(_instance==0)
      {
          const char* mazeStyle=getenv("MAZESTYLE");
          if(strcmp(mazeStyle,"bombed")==0)
             _instance=new BombedMazeFactory;
          else if(strcmp(mazeStyle,"enchanted")==0)
            _instance=new EnchantedMazeFactory;
            //...other possible subclasses
            else
            _instance=new  MazeFactorySingle; //default
      }
      return _instance;
}

Related Parrerns
Many patterns can be implemented using the Singleton pattern.See Abstract Factory,Builder,and Prototype.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值