2013-05-29 9 views
8

ich, um Code in C++ versucht (11 C++) ein sehr einfaches Beispiel nach dem Clean Architecture Konzept beschrieben von Uncle Bob Martin here (Bild unten):nicht so sauber Architektur

enter image description here

Die Idee ist, etwas Text von einem Controller zu lesen und es von einem Presenter zu drucken. Ich habe etwas gemacht, aber es sieht nicht so aus, als ob es dem sauberen Fluss und dem DIP des Blogposts folgt.

Unter anderem denke ich, dass der Fluss falsch ist, wie zum Beispiel der IUseCaseInputPort über den IUseCaseOutputPort wissen muss (die Lesefunktion hat den IUseCaseOutputPort als Eingabeparameter, wodurch eine weitere Abhängigkeit erzeugt wird ...).

Ich würde mich sehr freuen, wenn mir jemand Tipps geben könnte, wie man das am besten umsetzen kann. Vielen Dank im Voraus.

#include <iostream> 
#include <string> 
#include <memory> 

class IUseCaseOutputPort { 
public: 
    virtual void print(std::string message) = 0; 
    virtual ~IUseCaseOutputPort() {}; 
}; 

// 2 Presenters 
class HtmlPresenter: public IUseCaseOutputPort { 
public: 
    void print(std::string message) { 
     std::cout << "<p>" << message << "</p>" << std::endl; 
    } 
}; 

class TextPresenter: public IUseCaseOutputPort { 
public: 
    void print(std::string message) { 
     std::cout << message << std::endl; 
    } 
}; 

// 
class IUseCaseInputPort { 
public: 
    virtual void read(std::shared_ptr<IUseCaseOutputPort> output) = 0; 
    virtual ~IUseCaseInputPort(){}; 
}; 

// specific UseCaseInteractor 
class UseCaseInteractorForInputFromStdIn: public IUseCaseInputPort { 
public: 
    void read(std::shared_ptr<IUseCaseOutputPort> output) { 
     std::string message; 
     std::cout << "Please input some text!"; 
     std::getline(std::cin, message); 
     output->print(message); 
    } 
}; 

// Controller 
class ControllerToDisplayHtml { 
public: 
    void displayInHtmlSomethingFromStdIn() { 
     input = std::make_shared<UseCaseInteractorForInputFromStdIn>(); 
     std::shared_ptr<HtmlPresenter> output = 
       std::make_shared<HtmlPresenter>(); 
     input->read(output); 
    } 
private: 
    std::shared_ptr<IUseCaseInputPort> input; 
}; 

int main() { 
    ControllerToDisplayHtml c; 
    c.displayInHtmlSomethingFromStdIn(); 
    return 0; 
} 

Für interessierte die, wie von BЈовић vorgeschlagen eine Ergänzung zu meiner Frage. Sehr einfaches Beispiel. Nur um den Ablauf dieses Modells zu zeigen.

#include <iostream> 
#include <string> 
#include <memory> 
#include <fstream> 

class IUseCaseOutputPort { 
public: 
    virtual void print(std::string message) = 0; 
    virtual ~IUseCaseOutputPort() {}; 
}; 

// 2 Presenters 
class HtmlPresenter: public IUseCaseOutputPort { 
public: 
    void print(std::string message) { 
     std::cout << "<p>" << message << "</p>" << std::endl; 
    } 
}; 

class TextPresenter: public IUseCaseOutputPort { 
public: 
    void print(std::string message) { 
     std::cout << message << std::endl; 
    } 
}; 

// 
class IUseCaseInputPort { 
public: 
    virtual std::string read() = 0; 
    virtual ~IUseCaseInputPort(){}; 
}; 

// specific UseCaseInteractor for reading text from the stdin 
class UseCaseInteractorForInputFromStdIn: public IUseCaseInputPort { 
public: 
    std::string read() { 
     std::string message; 
     std::cout << "Please input some text!" << std::endl; 
     std::getline(std::cin, message); 
     return message; 
    } 
}; 

// specific UseCaseInteractor for reading text from a dummy file 
class UseCaseInteractorForInputFromDummyFile: public IUseCaseInputPort { 
public: 
    std::string read() { 
     const std::string filename = "/proc/meminfo"; 
     std::string message = readFile(filename); 
     return message; 
    } 
private: 
    std::string readFile(const std::string filename) { 
     std::string line; 
     std::string lines; 
     std::ifstream myfile(filename); 
     if (myfile.is_open()) { 
      while (myfile.good()) { 
       getline(myfile, line); 
       lines += line + '\n'; 
      } 
      myfile.close(); 
     } else { 
      lines = "Unable to open file"; 
     } 
     return lines; 
    } 
}; 

// Controller 
class ControllerForReading { 
public: 
    std::string readFromStdIn() { 
     input = std::make_shared<UseCaseInteractorForInputFromStdIn>(); 
     std::string out = "This text was read from the stdin:\n"; 
     out += input->read(); 
     return out; 
    } 
    std::string readFromFile() { 
     input = std::make_shared<UseCaseInteractorForInputFromDummyFile>(); 
     std::string out = "This text was read from the a file:\n"; 
     out += input->read(); 
     return out; 
    } 
private: 
    std::shared_ptr<IUseCaseInputPort> input; 
}; 

// main represents the outer shell 
int main() { 
    std::cout << "Main started!" << std::endl; 

    ControllerForReading c; 
    const std::string textFromStdin = c.readFromStdIn(); 
    const std::string textFromFile = c.readFromFile(); 

    auto output = std::make_shared<HtmlPresenter>(); 
    output->print(textFromStdin); 
    output->print(textFromFile); 

    auto output2 = std::make_shared<TextPresenter>(); 
    output2->print(textFromStdin); 
    output2->print(textFromFile); 

    std::cout << "Main ended!" << std::endl; 
    return 0; 
} 
+3

Wenn Ihre Frage wirklich über Code-Stil (anstatt über einen Fehler) ist, sollten Sie es wahrscheinlich auf http://codereview.stackexchange.com fragen. –

+0

Danke. Es sieht weder wie Bug noch Code-Stil aus ... Ich will nur die zusätzliche Abhängigkeit vermeiden, die ich eingeführt habe. Wenn ich keine Antworten bekomme, poste ich es dort, wo du es vorgeschlagen hast. – RicLeal

Antwort

4

Unter anderem denke ich, die Strömung falsch ist, wie zum Beispiel die IUseCaseInputPort über den IUseCaseOutputPort wissen muss (die Lesefunktion den IUseCaseOutputPort als Eingangsparameter hat, so dass ein andere Abhängigkeit zu schaffen ...).

Ja, das ist in der Tat falsch. Eine Methode zum Abrufen von Daten sollte nicht wissen, was damit gemacht wird.

Eine Lösung ist ziemlich einfach. Ändern IUseCaseInputPort::read Methode das Ergebnis zurückzukehren, statt IUseCaseOutputPort Methode Aufruf:

// 
class IUseCaseInputPort { 
public: 
    virtual std::string read() = 0; 
    virtual ~IUseCaseInputPort(){}; 
}; 

// specific UseCaseInteractor 
class UseCaseInteractorForInputFromStdIn: public IUseCaseInputPort { 
public: 
    std::string read() { 
     std::string message; 
     std::cout << "Please input some text!"; 
     std::getline(std::cin, message); 
     return message; 
    } 
}; 

// Controller 
class ControllerToDisplayHtml { 
public: 
    void displayInHtmlSomethingFromStdIn() { 
     input = std::make_shared<UseCaseInteractorForInputFromStdIn>(); 
     std::shared_ptr<HtmlPresenter> output = 
       std::make_shared<HtmlPresenter>(); 

     const std::string messageToOutput(input->read()); 
     output->print(messageToOutput); 
    } 
private: 
    std::shared_ptr<IUseCaseInputPort> input; 
}; 

Eine weitere Sache. Sie sollten keine Eingabe- und Ausgabeobjekte in der displayInHtmlSomethingFromStdIn()-Methode erstellen. Stattdessen sollten Sie eine Art Abhängigkeitsinjektion verwenden. Das heißt, Sie erstellen diese Objekte außerhalb und übergeben sie durch einen Zeiger oder Verweis auf das Objekt ControllerToDisplayHtml.

+0

Danke! Es ist jetzt viel besser! – RicLeal

+0

Danke für den Tipp. Das war nur ein Test. Ich werde ein passendes Beispiel unter meiner Frage veröffentlichen. – RicLeal

Verwandte Themen