The prototype mode specifies the type that needs to be created through the instance object, which is essentially different from the factory method pattern, where the factory method pattern is defined by the inheritance of the class to create different types of objects, belonging to the class pattern, The prototype mode generates different types of object instances by calling the grouped object members, which belong to the object pattern.
Due to this feature, prototype has the following applicable occasions:
· When the runtime is required to determine the instantiated class, such as dynamic loading libraries
· Avoid creating too many child classes. Too many subclasses are always unwelcome, in factory method we also mention reducing the number of subclasses by template or parameterization.
· When the state combination of instantiated objects is too large, it is more convenient to build the prototype library so that the target object can be generated by using the registry to obtain the corresponding prototype.
The advantages of prototype include:
· Add and remove products at run time
· Changing objects, this is the common advantage of combinatorial patterns
· Reduce the number of subclasses
· Dynamically configuring Applications with classes
The biggest disadvantage of prototype is that it can be difficult to implement a clone operation in some languages, especially if the amount of circular references is included.
Next, continue to use the example in the previous article, develop a chip design software, with prototype implementation. All graphics inherit from Maskfigure, you must implement the Clone function, Maskdesigner incoming object prototype pointer when initializing, makefigure generate new graphics through clone of the prototype. Factory method is a graph corresponding to the class call the graph class constructor to generate a new object, popular point, as if Factory method is to use the design drawings to redraw a graphic, and prototype is a copy of the graphic has been painted. The class structure is as follows:
The code implementation is as follows:
//mask.hpp
#ifndef MASK_HPP
#define MASK_HPP
class MaskFigure{
public:
virtual ~MaskFigure()=0;
virtual MaskFigure* clone()=0;
protected:
MaskFigure();
MaskFigure(const MaskFigure&);
};
class MaskRound:public MaskFigure {
public:
MaskRound();
MaskRound(const MaskRound&);
MaskRound* clone();
~MaskRound();
};
class MaskRec:public MaskFigure {
public:
MaskRec();
MaskRec(const MaskRec&);
MaskRec* clone();
~MaskRec();
};
class MaskTri:public MaskFigure {
public:
MaskTri();
MaskTri(const MaskTri&);
MaskTri* clone();
~MaskTri();
};
#endif
//mask.cpp
#include <iostream>
#include "mask.hpp"
using std::cout;
using std::endl;
MaskFigure::MaskFigure() {
cout<<"init MaskFigure"<<endl;
}
MaskFigure::MaskFigure(const MaskFigure& mf) {
cout<<"copy Figure"<<endl;
}
MaskFigure::~MaskFigure() {
cout<<"delete MaskFigure"<<endl;
}
MaskRound::MaskRound() {
cout<<"Draw roundness on Mask"<<endl;
}
MaskRound::MaskRound(const MaskRound& mr) :MaskFigure(mr){
cout<<"copy roundness"<<endl;
}
MaskRound* MaskRound::clone() {
return new MaskRound(*this);
}
MaskRound::~MaskRound() {
cout<<"delete MaskRound"<<endl;
}
MaskRec::MaskRec() {
cout<<"Draw rectangle on Mask"<<endl;
}
MaskRec::MaskRec(const MaskRec& mr) :MaskFigure(mr){
cout<<"copy rectangle"<<endl;
}
MaskRec* MaskRec::clone() {
return new MaskRec(*this);
}
MaskRec::~MaskRec() {
cout<<"delete MaskRec"<<endl;
}
MaskTri::MaskTri() {
cout<<"Draw triangle on Mask"<<endl;
}
MaskTri::MaskTri(const MaskTri& mt) :MaskFigure(mt){
cout<<"copy triangle"<<endl;
}
MaskTri* MaskTri::clone() {
return new MaskTri(*this);
}
MaskTri::~MaskTri() {
cout<<"delete MaskTri"<<endl;
}
//maskdesigner.hpp
#ifndef FIGUREDESIGNER_HPP
#define FIGUREDESIGNER_HPP
#include "mask.hpp"
class FigureDesigner{
public:
FigureDesigner(MaskFigure *mf){
figure = mf;
}
MaskFigure* MakeFigure(){
return figure->clone();
}
private:
MaskFigure *figure;
};
#endif
//main.cc
#include <memory>
#include <iostream>
#include "maskdesigner.hpp"
using std::cout;
using std::endl;
using std::shared_ptr;
int main() {
MaskRound mro;
MaskRec mre;
MaskTri mtr;
FigureDesigner md1(&mro);
shared_ptr<MaskFigure> mfptr1(md1.MakeFigure());
FigureDesigner md2(&mre);
shared_ptr<MaskFigure> mfptr2(md2.MakeFigure());
FigureDesigner md3(&mtr);
shared_ptr<MaskFigure> mfptr3(md3.MakeFigure());
}
Speaking of prototype mode, it is necessary to mention the C + + covariance characteristics, namely, C + + covariant nature, in the virtual function implementation, the general requirements derived classes to override the virtual function must be consistent with the base class function return value type, number of parameters and type.
However, there is a special case where the return value type can be different if it satisfies the following criteria.
1. Base class and derived class virtual function return value types are pointers to classes or references
2. The base class virtual function returns the value pointer or reference to the class type that is the indirect or direct base class of the derived class return value pointer or reference to the class type, that is, the same inheritance system.
This means that the following conditions are allowed,
Class Base {/* ... */};
class Base { /* ... */ };
class Derived: public Base { /* ... */ };
class B {
virtual Base* func() { return new Base; }
virtual ~B() { }
};
class D: public B {
Derived* func() { return new Derived; }
virtual ~D() { }
};
The return values of Fanc are base* and derived*, which belong to the same inheritance system respectively. However, the return value is not allowed when it is converted to another type, such as a base type. This feature is fully applied in prototype, Maskfigure's clone function returns maskfigure* pointer type, MASKROUND,MASKREC and Masktri's clone function returns maskround* respectively, maskrec* and masktri* pointer types.