2013-12-16 69 views
1

我最近在求職面試時,我的面試官的新對象給我,涉及不同形狀的序列化到一個文件中的建模問題。創建通過調用新構造函數的字符串

的任務是通過首先定義一個抽象名爲Shape類來實現的形狀像圓或矩形,然後通過從基類(形狀)繼承實現各種形狀(圓形,矩形。)。

每種形狀的兩種抽象方法是:read_to_file(應該從文件讀取形狀)和write_to_file,它應該將形狀寫入文件中。

所有的工作都是通過在繼承的形狀中實現該虛擬函數來完成的(例如:對於Circle我正在寫入半徑,對於正方形我保存了正方形的邊......)。

class Shape { 
public: 
    string Shape_type; 

    virtual void write_into_file()=0; 

    virtual void read_into_files()=0; 

    Shape() { 
    } 
    virtual ~Shape() { 
    }}; 
class Square: public Shape { 
public: 
    int size; 
    Square(int size) { 
     this->size = size; 
    } 
    void write_into_file() { 
     //write this Square into a file 
    } 
    void read_into_files() { 
     //read this Square into a file 
    } 
}; 

這樣做是爲了看看我是否知道多態性。

但是,後來我被要求執行該採取的*shape向量兩種功能和讀/寫它到一個文件中。

書寫的內容很簡單,去這樣的事情:

for (Shape sh : Shapes) { 
    s.write_into_file(); 
} 

爲我想過在文本閱讀的第一個字的閱讀部分(我實現這樣的有這個文本文件中的序列化的文件線:Shape_type: Circle, Radius: 12; Shape_type:Square....,所以第一句話說的形狀類型)。並將其保存到一個字符串,如:

string shape_type; 
shape_type="Circle"; 

然後我需要創建一個特定形狀的新實例,我想的東西就像一個大的開關

<pre><code> 
switch(shape_type): 
{ 
case Circle: return new circle; 
case Square: return new square 
...... 
} 
</pre></code> 

然後,面試官告訴我認爲這個實現有一個問題,我認爲這是一個事實,即我們將在未來添加的每一個新形狀都應該更新int這個大的形狀。他試圖引導我進入設計模式,我告訴他,工廠設計模式可能會有所幫助,但我找不到擺脫這種轉變的方法。即使我將這個開關從功能移動到FactoryClass我仍然必須使用開關來檢查形狀的類型(根據我從文本文件中獲得的字符串內容)。

我有,我從文件中讀取一個字符串,表示當前類型的形狀。我想做的事情如下:

string shape_type; 
shape_type="Circle"; 
Shape s = new shape_type; //which will be like: Shape s = new Circle 

但我不能在c + +中做到這一點。

對我應該做什麼有任何想法?

回答

1

在您的工廠中,您可以將std::string映射到function<Shape*()>。在啓動您註冊工廠方法將工廠:

shapeFactory.add("circle", []{new Circle;}); 
shapeFactory.add("square", []{new Square;}); 
shapeFactory.add("triangle", []{new Triangle;}); 

在你的反串行化代碼你讀的類型的名稱,並從工廠拿到的工廠方法:

std::string className = // read string from serialization stream 
auto factory = shapeFactory.get(className); 
Shape *shape = factory(); 

現在,您已經有了一個指向可用於反序列化對象的具體形狀實例的指針。

編輯:根據要求添加更多的代碼:

class ShapeFactory 
{ 
private: 
    std::map<std::string, std::function<Shape*()> > m_Functions; 

public: 

    void add(const std::string &name, std::function<Share*()> creator) 
    { 
    m_Functions.insert(name, creator) 
    } 

    std::function<Shape*()> get(const std::string &name) const 
    { 
    return m_Functions.at(name); 
    } 
}; 

注意:我省略了錯誤檢查。

+0

我如何製作這張地圖?寄存器是C++中的保留字嗎? – Matoy

+0

我添加了一些代碼,並將其名稱更改爲'add',希望能夠使其更清晰。 – Sean

+1

謝謝!這似乎是我的面試官所要面對的答案(在30分鐘的面試中......去圖)。無論如何,你的答案引導我到谷歌,我發現這篇文章:http://blog.fourthwoods.com/2011/06/04/factory-design-pattern-in-c/(這基本上更遠一點litlle多一點在你的右邊回答。謝謝。 – Matoy

0

在C++中,用

for (Shape sh : Shapes) { 
    s.write_into_file(); 
} 

你有object slicing。對象sh是一個Shape,沒有別的,它丟失了所有的繼承信息。

您或者需要存儲引用(不可能存儲在標準集合中)或指針,並在循環時使用它。

+0

不正確。 int main(){ \t Shape * s = new Sqaure(20); \t s-> print_type(); //方格 } – Matoy

+0

@ user1007665是的,但是您沒有* slicing *。請閱讀提供的鏈接。 –

0

在C++中,您需要在文件中讀寫某種類型的標籤以記住具體的類型。

像ShapeType get_type_tag()這樣的虛擬方法會這樣做,其中返回類型是與具體類之一相對應的枚舉。

想一想,雖然這個問題可能只是想讓你在界面上添加讀寫功能。

0

您可以創建由形狀名稱或形狀ID(shape_type)鍵入的工廠函數字典。

// prefer std::shared_ptr or std::unique_ptr of course 
std::map<std::string, std::function<Shape *()>> Shape_Factory_Map; 

// some kind of type registration is now needed 
// to build the map of functions 
RegisterShape(std::string, std::function<Shape *()>); 
// or some kind of 
BuildShapeFactoryMap(); 

// then instead of your switch you would simply 
//call the appropriate function in the map 
Shape * myShape = Shape_Factory_Map[shape_type](); 

在這種情況下,雖然你還是要更新你拿出更高版本的任何新的形狀地圖的創作,所以我不能肯定它給你買所有的東西說。

0

到目前爲止所有的答案似乎都必須使用開關或地圖來知道使用哪個類來創建不同類型的形狀。如果您需要添加其他類型,則必須修改代碼並重新編譯。

也許使用Chain of Responsibility模式是一種更好的方法。這樣,您可以動態添加新的創建技術或在編譯時添加它們,而無需修改任何現有代碼:

您的鏈將保留所有創建類型的鏈接列表,並遍歷列表,直到找到可以制定指定的類型。

class Creator{ 
    Creator*next; // 1. "next" pointer in the base class 
public: 
    Creator() 
    { 
    next = 0; 
    } 
    void setNext(Creator*n) 
    { 
     next = n; 
    } 
    void add(Creator*n) 
    { 
     if (next) 
     next->add(n); 
     else 
      next = n; 
    } 
    // 2. The "chain" method in the Creator class always delegates to the next obj 
    virtual Shape handle(string type) 
    { 
     next->handle(i); 
    } 
); 

造物主的每個子類都將檢查它是否能使類型,如果它可以退貨,或委託給鏈中的下一個。

0

前段時間,我在C++中創建了一個工廠,其中一個類在擴展給定模板時在編譯時自動註冊自身。

可在這裏:https://gist.github.com/sacko87/3359911

我不太確定人們如何對SO以外的鏈接做出反應,但它是一對值得的文件。但是,一旦工作完成,使用該鏈接中的示例,您需要做的工作就是將一個新對象包含在工廠中,然後擴展BaseImpl類並使用靜態字符串「Name」字段(請參閱main.cpp )。模板然後自動將字符串和類型註冊到地圖中。讓你打電話:

Base *base = BaseFactory::Create("Circle"); 

你當然可以取代基地形狀。

相關問題