C ++中的策略模式。实施选项 [英] Strategy pattern in C++. Implementation options

查看:121
本文介绍了C ++中的策略模式。实施选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里有一个简单的例子:(我希望 - 请纠正我,如果我错了)战略模式:有一个类 FileWriter 它将键值对写入文件,并使用 IFormatter 接口的对象来格式化正在写入的文本。当创建 FileWriter 时,会传递不同的格式化程序实现和格式化对象。
这是一个(坏的)这种模式的实现:

  #include< iostream> 
#include< fstream>
#include< stdlib.h>
#include< sstream>

using namespace std;

类IFormatter {
public:
虚拟字符串格式(字符串键,双值)= 0;
};

class JsonFormatter:public IFormatter {
public:
string format(string key,double value){
stringstream ss;
ss<< \+ key +\:<值;
return ss.str();
}
};

class TabFormatter:public IFormatter {
public:
string format(string key,double value){
stringstream ss;
ss<< key +\t<<值;
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_;
};

可以看出,这种方法的主要缺点是不可靠 - Formatter 传递给的对象FileWriter 必须存在于整个 FileWriter 直接导向 SegFault



在这方面,我想讨论一下什么可能是用易于使用和简单需求实现这种方法的其他选项: / p>


  • 创建文件编写器时可传递新的格式化程序,或

  • 并使用。



我想出了以下描述的其他缺点(IMO):




  • 模板:具有 FileWriter FormatterClass 作为参数; 难以调用: FileWriter< JsonFormatter>(test.txt,JsonFormatter
  • 原始指针: FileWriter(test.txt,new JsonFormatter )); 缺点 - 谁应该删除formatter对象? FileWriter ?如果是,则传递现有格式化程序的地址将导致 SegFault 一次 FileWriter 对象尝试删除格式化程序。 li>
  • 共享指针: FileWriter(test.txt,dynamic_pointer_cast< IFormatter *>(shared_ptr< JsonFormatter *>(new JsonFormatter ))); 缺点:丑陋的调用,再次,如果formatter是在创建文件编写器之前创建的?



这里最好的做法是什么?



UPDATE



响应建议使用 std :: function 的答案 - 如果Formatter可以存储状态(比如说,精度)并且有其他方法 getHeader(),例如,对于CSV文件?



/ code> by value是不可能的,因为它是一个抽象类。

解决方案

  JsonFormatter formatter; 
FileWriter writer(test.txt,formatter);
//使用writer。

另一个更好的选择是有一个克隆)函数 IFormatter 。然后, FileWriter 可以克隆对象,获取克隆的所有权并在其析构函数中删除它。

  class IFormatter {
public:
virtual string format(string key,double value)= 0;
virtual IFormatter * clone()const = 0;
};


class FileWriter {
public:

FileWriter(string fname,IFormatter const& fmt):fmt_(fmt.clone $ b {
f_.open(fname.c_str(),ofstream :: out);
}

〜FileWriter()
{
delete fmt_;
}

void writePair(string key,double value)
{
f_< fmt _-> format(key,value);
}

private:
ofstream f_;
IFormatter * fmt_;
};

现在,您可以使用临时文件调用 FileWriter 对象也。

  FileWriter writer(test.txt,JsonFormatter()); 
//使用writer。


Here's a simplified example of what is called (I hope - please, correct me if I'm wrong) Strategy pattern: there's a class FileWriter which writes key-value pairs to a file and uses object of IFormatter interface for formatting text being written. There are different formatters implementations and formatter object is passed when FileWriter is created. Here's one (bad) implementation of such pattern:

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

As can be seen, the main drawback of such approach is it's unreliability - Formatter object passed to FileWriter has to exist during whole FileWriter's lifetime, thus calls like FileWriter("test.txt", JsonFormatter()) lead directly to SegFault.

In this regard, I'd like to discuss what could be the other options for implementing such an approach with "easy-to-use" and simplicity requirements:

  • either new formatter can be passed when file writer is created, or
  • existing formatter can be passed and used.

I came up with several alternatives described below with their drawbacks (IMO):

  • templates: having FileWriter as a template class which takes exact FormatterClass as an argument; drawback: ugly to call: FileWriter<JsonFormatter>("test.txt", JsonFormatter()) - here, JsonFormatter is typed twice.
  • raw pointers: FileWriter("test.txt", new JsonFormatter()); drawback - who should delete formatter object? FileWriter? if yes, then passing an address of existing formatter will lead to SegFault once FileWriter object attempts to delete formatter.
  • shared pointers: FileWriter("test.txt", dynamic_pointer_cast<IFormatter*>(shared_ptr<JsonFormatter*>(new JsonFormatter())); drawback: ugly to call, and again, what if formatter was created before creating file writer?

What would be the best practices here?

UPDATE

In response to answers that suggested to use std::function - What if Formatter may store a state (say, precision) and have additional methods, like getHeader(), for instance, for CSV files?

Additionaly, storing IFormatter by value isn't possible since it's an abstract class.

解决方案

The simplest solution is to use:

JsonFormatter formatter;
FileWriter writer("test.txt", formatter);
// Use writer.

The other option that is a little bit better is to have a clone() function in IFormatter. Then, FileWriter can clone the object, take ownership of the clone and delete it in its destructor.

 class IFormatter {
   public:
     virtual string format(string key, double value) = 0;
     virtual IFormatter* clone() const = 0;
 };


 class FileWriter {
   public:  

     FileWriter(string fname, IFormatter const& fmt):fmt_(fmt.clone())
     {
         f_.open(fname.c_str(), ofstream::out);
     }

     ~FileWriter()
     {
        delete fmt_;
     }

     void writePair(string key, double value)
     {
         f_ << fmt_->format(key, value);
     }

   private:
     ofstream f_;
     IFormatter* fmt_;
 };    

Now, you can call FileWriter with temporary object too.

FileWriter writer("test.txt", JsonFormatter());
// Use writer.

这篇关于C ++中的策略模式。实施选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆