9

我正在尝试根据 Bob Martin 叔叔在这里描述的 Clean Architecture 概念用 C++ (C++11) 编写一个非常简单的示例(下图):

在此处输入图像描述

这个想法是由控制器读取一些文本并由演示者打印。我做了一些事情,但它看起来不像是遵循干净的流程和博客文章的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;
}
4

1 回答 1

5

除其他外,我认为流程是错误的,例如,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对象引用传递它们。

于 2013-05-29T10:59:56.017 回答