2

所以我有以下项目要完成。我还没有决定如何设计它。会喜欢一些建议。

它基本上是一个表格存档器。给定特定条件,您需要将这些行导出到另一个地方。这个地方可以是另一个数据库或(s)ftp 服务器。如果您选择一个数据库,您需要在每次达到特定限制时创建一个表(例如每个表不超过 50k 行),如果您选择一个 (s)ftp 服务器,那么您需要编写一个 CSV 或 XML 并将文件在那里。

所以我们有这些组合:

  1. sql2CustomerSql
  2. sql2Oursql(为此,我们已经根据系统配置进行了连接和获取一些信息的类)
  3. csv2ftp
  4. csv2sftp
  5. xml2ftp
  6. xml2sftp

现在,我到处都看到 AbstractFactory 模式,但基于什么?我的想法是我应该有 SQLWriter、XMLWriter、CSVWriter,它们都继承自一个抽象 Writer 类,该类实现一些常见的策略,如计数行、获取常见的配置参数等......我应该对 Connection 类/接口做同样的事情吗(因为sql 和 (s)ftp 真的不一样吗?

如果您需要更多信息,请询问。

4

3 回答 3

2

听起来你在正确的道路上。

您应该避免创建由 Writer 和 Connection 组合而成的类,而是创建某种包含(作为属性)Writer 接口和 Connection 接口的 Manager 类。然后创建每个适当的实现并将它们传递给 Manager。

这是策略设计模式的经典用法。

编辑:添加代码示例。您应该添加适当的错误检查。

class Writer
{
public:
    virtual void output(cons std::string &data) = 0;
};

class Format
{
public:
    virtual std::string serialize() = 0;
};

// Create concrete Writer and Format classes here

class OutputManager
{
public:
    // Notice there should be no Writer, Format creation logic here,
    // This class should focus on orchestrating the output
    OutputManager() : writer_(NULL), format_(NULL) {}
    OutputManager(Writer *w, Format *f) : writer_(w), format_(f) {}

    void setWriter(Writer *w) { writer_ = w; }
    Writer *getWriter()       { return writer_; }

    void setFormat(Format *f) { format_ = f; }
    Format *getFormat()       { return format_; }

    // Maybe this should have a different return type
    void doOutput()
    {
        // Not sure what else you would need here,
        // but this is an example usage
        writer_->output(format_->serialize());
    }

private:
    Writer *writer_;
    Format *format_;
};

//
// And now the factories
//
class OutputAbstractFactory
{
public:
    OutputAbstractFactory(Config *c) config_(c) {}
    void createFactories()
    {
        writerFactory_ = WriterAbstractFactory::getWriterFactory(config_);
        formatFactory_ = FormatAbstractFactory::getFormatFactory(config_);
    }

    Writer *getWriter() { return writerFactory_->getWriter(); }
    Format *getFormat() { return formatFactory_->getFormat(); }

private:
    WriterAbstractFactory *writerFactory_;
    FormatAbstractFactory *formatFactory_;
    Config *config_;
}

class WriterAbstractFactory
{
public:
    // Config is a class you will have to make with 
    // the info detailing the Writer and Format stuff
    static WriterAbstractFactory *getWriterFactory(Config *c);
    virtual Writer *getWriter() = 0;
};

class FormatAbstractFactory
{
public:
    // Config is a class you will have to make with
    // the info detailing the Writer and Format stuff
    static FormatAbstractFactory *getFormatFactory(Config *c);
    virtual Format *getFormat() = 0;
};

// Create concrete factories here

//
// And this ties it all together
//
int main(int argc, char **argv)
{
    Config c;
    // populate Config accordingly

    OutputAbstractFactory *factory(&c);
    factory.createFactories();

    Writer *w = factory->getWriter();
    Format *f = factory->getFormat();
    // Do whatever else you need to with the Writer/Format here

    OutputManager om(w, f);
    // Do whatever else you need with the OutputManager here
    om.doOutput();
}
于 2012-04-27T11:10:13.113 回答
0

您可能想要获取一份Modern C++ Design的副本,以获取有关如何制作基于策略的通用转换工具的想法。下面是一个非常粗略的框架,它在两个策略上进行了参数化:格式和连接。

template
<
    typename FormatPolicy,    // SQL, XML, CSV, provides row, config functionality
    typename ConnectionPolicy // SQL, FTP, provides open/close/read/write functionality
>
class ConversionTool
: 
    public FormatPolicy,
    public ConnectionPolicy
{
public:
    // your conversion interface here
    void operator()( /* your input */, /* your output */);
};

class SQLFormat { // SQL specific stuff } ;
class SQLConnection { // SQL specific stuff };

typedef ConversionTool<SQLFormat, SQLConnection> SQL2OurCustomerSQL;
SQL2OurCustomerSQL()(in_file, out_file); // for elsewhere declared in_file / out_file
于 2012-04-27T12:37:54.657 回答
0

您正在处理两个问题。一个是格式,另一个是持久化的目的地。对于格式,您需要序列化程序,对于目标,您需要适配器。SqlSerializer、XMLserializer。SQLDestination、FTPDestination 等。

伪代码如下所示:

  • Destination.persist(new Serializer(SourceData));
  • Destination.persist(Serializer.transform(SourceData));
  • 新目的地(新序列化程序(源数据)).persist();

    interface DataSerializer{
        String serialize();
    }
    
    class SqlSerializer implements DataSerializer {
        final Object rawData;
    
        SqlSerializer(Object rawData) {
            this.rawData = rawData;
        }
    
        String serialize() {
            // SQL Serialization Logic
        }
    }
    
    class XmlSerializer implements DataSerializer {
        final Object rawData;
    
        XmlSerializer(Object rawData) {
           this.rawData = rawData;
        }
    
        String serialize() {
            // XML Serialization Logic
        }
    }
    
    interface Destination {
        void persist(DataSerializer dataSerializer);
    }
    
    class SqlDestination implements Destination {
        final String username;
        ...
        ...
    
        SqlDestination(String username, String password, String url) {
            this.username = username;
            ...
            ...
        }
    
        void persist(DataSerializer dataSerializer) {
            // open SQL connection
            String = dataSerialize.serialize();
            // do sqlPersistanceLogic
        }
    }
    
    class FtpDestination implements Destination {
        final String username;
        ...
        ...
    
        FtpDestination(String username, String password, String url) {
            this.username = username;
            ...
            ...
        }
    
        void persist(DataSerializer dataSerializer) {
            // open FTP session connection
            String = dataSerialize.serialize();
            // send to ftpDestination
        }
    }
    
    Call:
    
    Destination dest = getApropriateDestination();
    dest.persist(new XmlSerializer(rawData));
    

您还可以实现逻辑来验证特定目标支持的序列化程序,或者如果目标和序列化程序之间存在 1:1 关系,您可以使用模板。但我不知道它在 C++ 中是怎样的;

根据您使用的工具和框架,您可以实施三种建议的方式之一。原则仍然存在

于 2012-04-27T13:14:32.380 回答