2013-05-29 3 views
8

Я пытаюсь кода в C++ (C++ 11) очень простой пример, в соответствии с концепцией Clean Architecture описываемого Дяди Боба Мартина here (рисунок ниже):Не так Чистая архитектура

enter image description here

Идея состоит в том, чтобы прочитать текст с помощью контроллера и распечатать его презентатором. Я сделал что-то, но не похоже, что он следит за чистым потоком и DIP из сообщения в блоге.

Помимо прочего, я считаю, что поток неправильный, поскольку, например, IUseCaseInputPort должен знать об IUseCaseOutputPort (функция чтения имеет входной параметр IUseCaseOutputPort, создавая при этом еще одну зависимость ...).

Я был бы очень признателен, если бы кто-нибудь мог дать мне несколько советов о лучшем способе реализовать это. Большое спасибо заранее.

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

Для тех, кто заинтересован, дополнение к моему вопросу, как предложено BЈовић. Очень простой пример. Просто чтобы показать поток этой модели.

#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

Если ваш вопрос действительно о стиле кода (а не об ошибке), вы должны, вероятно, задать его по адресу http://codereview.stackexchange.com. –

+0

Спасибо. Это не выглядит ни как ошибка, ни стиль кода ... Просто хочу избежать дополнительной зависимости, которую я представил. Если я не получу никаких ответов, отправлю его там, где вы предложили. – RicLeal

ответ

4

Среди прочего, я думаю, что поток не так, как, например, IUseCaseInputPort должен знать о IUseCaseOutputPort (функция чтения имеет IUseCaseOutputPort в качестве входного параметра, создавая при этом другую зависимость ...).

Да, это действительно неправильно. Метод получения данных не должен знать, что с ним делается.

Исправление довольно простое. Изменение IUseCaseInputPort::read метод возвращает результат, вместо вызова метода IUseCaseOutputPort в:

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

еще одна вещь. Не следует создавать объекты ввода и вывода в методе displayInHtmlSomethingFromStdIn(). Вместо этого вы должны использовать какую-то инъекцию зависимости. Это означает, что вы создаете эти объекты снаружи и передаете их через указатель или ссылку на объект ControllerToDisplayHtml.

+0

Спасибо! Сейчас намного лучше! – RicLeal

+0

Спасибо за подсказку. Это был просто тест. Я поставлю соответствующий пример ниже моего вопроса. – RicLeal

Смежные вопросы