【发布时间】:2016-03-12 01:46:14
【问题描述】:
这是所谓的简化示例(我希望 - 如果我错了,请纠正我)策略 模式:有一个类 FileWriter 将键值对写入文件并使用IFormatter 接口的对象来格式化正在写入的文本。有不同的格式化程序实现,并且在创建 FileWriter 时传递格式化程序对象。
这是这种模式的一个(不好的)实现:
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <sstream>
using namespace std;
class IFormatter {
public:
virtual string format(string key, double value) = 0;
};
class JsonFormatter : public IFormatter {
public:
string format(string key, double value) {
stringstream ss;
ss << "\""+key+"\": " << value;
return ss.str();
}
};
class TabFormatter : public IFormatter {
public:
string format(string key, double value) {
stringstream ss;
ss << key+"\t" << value;
return ss.str();
}
};
class FileWriter {
public:
FileWriter(string fname, IFormatter& fmt):fmt_(fmt)
{
f_.open(fname.c_str(), ofstream::out);
}
void writePair(string key, double value)
{
f_ << fmt_.format(key, value);
}
private:
ofstream f_;
IFormatter& fmt_;
};
可以看出,这种方法的主要缺点是它的不可靠性 - 传递给FileWriter 的Formatter 对象必须在FileWriter 的整个生命周期中都存在,因此像@ 这样的调用987654328@直接转至SegFault。
在这方面,我想讨论一下实现这种具有“易于使用”和简单要求的方法的其他选择:
- 可以在创建文件写入器时传递新的格式化程序,或者
- 现有的格式化程序可以传递使用。
我想出了下面描述的几种替代方案及其缺点 (IMO):
-
模板: 将
FileWriter作为模板类,将精确的FormatterClass作为参数; 缺点: 难看:FileWriter<JsonFormatter>("test.txt", JsonFormatter())- 这里,JsonFormatter被输入了两次。 -
原始指针:
FileWriter("test.txt", new JsonFormatter()); 缺点 - 谁应该删除格式化程序对象?FileWriter?如果是,那么一旦FileWriter对象尝试删除格式化程序,传递现有格式化程序的地址将导致SegFault。 -
共享指针:
FileWriter("test.txt", dynamic_pointer_cast<IFormatter*>(shared_ptr<JsonFormatter*>(new JsonFormatter())); 缺点: 很难调用,如果在创建文件编写器之前创建了格式化程序会怎样?
这里的最佳做法是什么?
更新
针对建议使用 std::function 的答案 - 如果 Formatter 可以存储状态(例如精度)并具有其他方法(例如 getHeader())用于 CSV 文件怎么办?
此外,无法按值存储IFormatter,因为它是一个抽象类。
【问题讨论】:
标签: c++ templates pointers shared-ptr strategy-pattern