我想在C++编写代码(C++ 11)根据鲍勃叔叔马丁所描述的清洁建筑理念很简单的例子在这里(下图):

这个想法是由Controller读取一些文本并由Presenter打印.我已经做了一些事情,但它看起来并不像它正在遵循博客文章的干净流程和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;
}
Run Code Online (Sandbox Code Playgroud)
对于那些感兴趣的人,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;
}
Run Code Online (Sandbox Code Playgroud)
除此之外,我认为流程是错误的,例如,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;
};
Run Code Online (Sandbox Code Playgroud)
还有一件事.您不应该在displayInHtmlSomethingFromStdIn()方法中创建输入和输出对象.相反,你应该使用某种依赖注入.这意味着,您可以在外部创建这些对象,并通过指针或对该ControllerToDisplayHtml对象的引用传递它们.