工廠模式
工廠模式(Factory Pattern)是面向對象程序設計中最常用的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且通過使用一個共同的接口來指向新創建的對象。
介紹
意圖: 定義一個創建對象的接口,使其子類自己決定實例化哪一個工廠類,工廠模式使其創建過程延遲到子類進行。
主要解決: 主要解決接口選擇的問題。
何時使用: 當我們明確計劃在不同條件下創建不同實例時。
如何解決: 使其子類實現工廠接口,返回的也是一個抽象的產品。
關鍵代碼: 創建過程在其子類執行。
應用實例: 如果我們需要一輛汽車,可以直接從工廠裏提貨,而不用管這輛汽車是怎麼被製造以及具體實現的。
優點:
-
一個調用者想創建一個對象,只需要知道其名稱。
-
擴展性高,如果想增加一個產品,只需要擴展一個工廠類(工廠方法模式)。
-
屏蔽了產品的具體實現,調用者只需要關心產品的接口。
缺點: 每次增加一個產品時,都需要增加一個具體類和對象實現工廠 (工廠方法模式),使得系統中類的個數成倍增加,在一定程度上增加了系統的複雜度,同時也增加了系統具體類的依賴。
實現
以下使用 C++ 定義一個 Shape
接口以及實現 Shape
接口的子類。
class Shape {
public:
virtual void draw() = 0;
};
class Rectangle : public Shape {
private:
int height = 0, width = 0;
public:
Rectangle() {}
Rectangle(int h, int w) {
height = h;
width = w;
}
void draw() {
std::cout << "Inside Rectangle::draw() method." << std::endl;
for (int i = 0; i < height; i++, std::cout << std::endl)
for (int j = 0; j < width; j++)
std::cout << "*";
std::cout << std::endl;
}
};
class Square : public Shape {
private:
int side = 0;
public:
Square() {}
Square(int s) {
side = s;
}
void draw() {
std::cout << "Inside Square::draw() method." << std::endl;
for (int i = 0; i < side; i++, std::cout << std::endl)
for (int j = 0; j < side; j++)
std::cout << "*";
std::cout << std::endl;
}
};
class Line : public Shape {
private:
int len = 0;
public:
Line() {}
Line(int l) {
len = l;
}
void draw() {
std::cout << "Inside Line::draw() method." << std::endl;
for (int i = 0; i < len; i++)
std::cout << "*";
std::cout << std::endl;
}
};
如果按照一般方法,我們在調用子類函數 draw()
前需要使用子類的構造函數來創建對象。
int main() {
Rectangle* r = new Rectangle(4, 5);
Square* s = new Square(3);
Line* l = new Line(10);
r->draw();
s->draw();
l->draw();
return 0;
}
輸出結果如下:
Inside Rectangle::draw() method.
*****
*****
*****
*****
Inside Square::draw() method.
***
***
***
Inside Line::draw() method.
**********
按照 Factory Pattern,我們不需要在創建子類對象時直接使用其構造函數。
定義工廠類 ShapeFactory
。
class ShapeFactory {
public:
static void printParaError() {
std::cout << "Parameter error!" << std::endl;
}
static void printTypeError() {
std::cout << "Type name error!" << std::endl;
}
static Shape* getShape(std::string type) {
if (type == "Rectangle") {
return new Rectangle();
}
if (type == "Square") {
return new Square();
}
if (type == "Line") {
return new Line();
}
printTypeError();
return nullptr;
}
static Shape* getShape(std::string type, std::vector<int> args) {
if (type == "Rectangle") {
if (args.size() == 2 && args[0] > 0 && args[1] > 0)
return new Rectangle(args[0], args[1]);
printParaError();
return nullptr;
}
if (type == "Square") {
if (args.size() == 1 && args[0] > 0)
return new Square(args[0]);
printParaError();
return nullptr;
}
if (type == "Line") {
if (args.size() == 1 && args[0] > 0)
return new Line(args[0]);
printParaError();
return nullptr;
}
printTypeError();
return nullptr;
}
};
創建工廠類 ShapeFactory
用以生成具體子類對象,再分別調用其函數 draw()
。
int main() {
ShapeFactory* f = new ShapeFactory();
Shape* r = f->getShape("Rectangle", { 4, 5 });
Shape* s = f->getShape("Square", { 3 });
Shape* l = f->getShape("Line", { 10 });
r->draw();
s->draw();
l->draw();
return 0;
}
以上爲 Simple Factory Pattern
簡單工廠模式,當增加新的子類時需要修改工廠類,不遵循開閉原則。
以下爲 Factory Method Pattern
工廠方法模式 :
class Factory {
public:
virtual Shape* getShape() = 0;
virtual Shape* getShape(std::vector<int> args) = 0;
static void printParaError() {
std::cout << "Parameter error!" << std::endl;
}
};
class RectangleFactory : public Factory {
public:
Shape* getShape() {
return new Rectangle();
}
Shape* getShape(std::vector<int> args) {
if (args.size() == 2 && args[0] > 0 && args[1] > 0)
return new Rectangle(args[0], args[1]);
Factory::printParaError();
return nullptr;
}
};
class SquareFactory : public Factory {
public:
Shape* getShape() {
return new Square();
}
Shape* getShape(std::vector<int> args) {
if (args.size() == 1 && args[0] > 0)
return new Square(args[0]);
Factory::printParaError();
return nullptr;
}
};
class LineFactory : public Factory {
public:
Shape* getShape() {
return new Line();
}
Shape* getShape(std::vector<int> args) {
if (args.size() == 1 && args[0] > 0)
return new Line(args[0]);
Factory::printParaError();
return nullptr;
}
};
int main() {
RectangleFactory* rf = new RectangleFactory();
SquareFactory* sf = new SquareFactory();
LineFactory* lf = new LineFactory();
Shape* r = rf->getShape({ 4, 5 });
Shape* s = sf->getShape({ 3 });
Shape* l = lf->getShape({ 10 });
r->draw();
s->draw();
l->draw();
return 0;
}