2013-05-29 17 views
8

Próbuję kodu w C++ (C++ 11) bardzo prosty przykład zgodnie z koncepcją Clean Architektury opisanej przez Uncle Bob Martin here (zdjęcie poniżej):nie tak czysty Architektura

enter image description here

Chodzi o to, aby przeczytać trochę tekstu przez kontroler i wydrukować go przez prezentera. Zrobiłem coś, ale nie wygląda na to, że podąża za czystym przepływem i DIP w poście na blogu.

Między innymi, myślę, że przepływ jest źle, jak na przykład IUseCaseInputPort musi wiedzieć o IUseCaseOutputPort (funkcja odczytu ma IUseCaseOutputPort jako parametr wejściowy, tworząc tym samym kolejną zależność ...).

będę naprawdę wdzięczny jeśli ktoś mógłby dać mi kilka wskazówek na temat najlepszego sposobu wdrożenia tego. Bardzo dziękuję z góry.

#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; 
} 

Dla zainteresowanych uzupełnieniem moje pytanie jak sugeruje BЈовић. Bardzo prosty przykład. Wystarczy pokazać przepływ tego modelu.

#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

Jeśli pytanie jest tak naprawdę o kodzie stylu (zamiast około bug), powinieneś poprosić go na http://codereview.stackexchange.com. –

+0

Dzięki. Nie przypomina to błędu ani stylu kodu ... Po prostu chcę uniknąć dodatkowej zależności, którą wprowadziłem. Jeśli nie otrzymam żadnych odpowiedzi, opublikuję go tam, gdzie zasugerowałeś. – RicLeal

Odpowiedz

4

Między innymi, myślę, że przepływ jest źle, jak na przykład IUseCaseInputPort musi wiedzieć o IUseCaseOutputPort (funkcja odczytu ma IUseCaseOutputPort jako parametr wejściowy, tworząc w ten sposób kolejną zależność ...).

Tak, rzeczywiście tak jest. Metoda uzyskiwania danych nie powinna wiedzieć, co się z nią dzieje.

Poprawka jest dość prosta. Zmień IUseCaseInputPort::read metodę zwraca wynik, zamiast wywoływania metody IUseCaseOutputPort za:

// 
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; 
}; 

jeszcze jedno. Nie powinieneś tworzyć obiektów wejściowych i wyjściowych w metodzie displayInHtmlSomethingFromStdIn(). Zamiast tego powinieneś użyć zastrzyku zależności. Oznacza to, że tworzysz te obiekty na zewnątrz i przekazujesz je przez wskaźnik lub odwołanie do obiektu ControllerToDisplayHtml.

+0

Dzięki! Teraz jest o wiele lepiej! – RicLeal

+0

Dzięki za cynk. To był tylko test. Postawię odpowiedni przykład poniżej mojego pytania. – RicLeal