C ++摆脱Singletons:替代函子和静态方法 [英] C++ getting rid of Singletons: alternative to functors and static methods

查看:198
本文介绍了C ++摆脱Singletons:替代函子和静态方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的崇高追求是摆脱单例和静态类.

背景:
我具有以下结构:

  • Cmd
    频繁实例化的对象,它包含命令的名称(字符串),以及指向任何类的静态方法的函数作为指针.
    它通常在主类(例如Input,Console)中创建,Render等,并引用在其创建的类中的方法,从而为这些方法提供运行时语言接口.
    Cmds还以字符串数组的形式解释参数,其中第一个参数是参数的名称. Cmd和所有连续的字符串都是所调用的静态方法的直接参数.参数计数和参数数组存储在Commander中,并在每次Cmd调用之前更改.
  • Commander
    Commander用于解释字符串命令(可以直接发出,也可以通过控制台发出),并执行作为字符串存储在缓冲区中的Cmd(通过调用函子来实现).

问题:
问题是我试图摆脱所有静态类(现在变成测试用的单例类),并且使系统成为完全模块化和松散耦合的.反过来,这使我无法获得Cmds可能指向的静态调用.

第一个直觉是将函子从typedef更改为模板类,该类将存储对象和方法,但看起来非常混乱和复杂,我个人不愿意从以下位置进行操作:

Cmd::create("toggleconsole", Console::toggle);

收件人:

Cmd::create("toggleconsole", new FunctorObject<Console>(&Console::get(), &Console::toggle));

最终的Cmd创作对于由谁负责Functor解除分配的工作看起来非常晦涩,并且具有误导性.

我还在将Cmd创建从静态方法调用转移到Commander类的过程中,因此看起来像是 commander.createCmd("command_name",...); Cmd :: create("command_name",...); 的原因是因为Commander不再是静态的(或单例),所以它处理的所有命令都必须属于它. /p>

但是,我完全不知道我要注册Cmds的选项/替代方法是什么,并通过允许将字符串命令发布给Commander来保持松散耦合.

我考虑过让每个主要类都派生自CmdListener类,该类将在创建时向Commander注册该对象,然后在执行过程中将命令传递给所有已注册对象,这些对象将覆盖"onCmd(const Cmd&命令).

这也留下了一些未解决的问题:Cmd将如何中继应调用哪种类方法?保持指针是没有意义的,并且会被高度模糊(如上所示).另外,我希望不要为可能处理该cmd的每个类在onCmd方法中重新解释字符串.

信息很多,但是有人对如何处理此问题有任何想法吗?

此外,我所有的课程都必须了解Commander和Console对象,它们不再是单例/静态的.到目前为止,我已经将它们放置在Context对象中,并像一个小胶囊一样传递它.关于如何解决这些后单残差问题有什么想法吗?

该项目是我的个人工作,我打算在简历中使用它-因此,我不希望潜在的雇主看到任何单身人士(也不想解释自己的原因,因为我可以证明对我自己来说,这并不是真正必要的.

一吨!

版式.

解决方案

这是function类的工作.您可以在Boost,TR1或C ++ 0x中找到一个.例如,它看起来像std::function<void()>.它通常与bind配合使用,如果要以通用方式引用而不是按值获取功能对象,则需要使用bind,并且在Boost,TR1或C中也可以找到它++ 0x.如果您有lambda函数,也可以使用它们,这是一种很好的方法.

class Commander {
    std::map<std::string, std::function<void()>> commands;
public:
    void RegisterCommand(std::string name, std::function<void()> cmd) {
        commands[name] = cmd;
    }
    void CallCommand(std::string name) {
        commands[name]();
    }
};
void sampleFunc() {
    std::cout << "sampleFunc()" << std::endl;
}
struct sampleStruct {
    int i;
    void operator()() {
        std::cout << i;
        std::cout << "sampleStruct()() and the value of i is " << i << std::endl;
    }
};

int main() {
    Commander c;
    c.RegisterCommand("sampleFunc", sampleFunc);
    sampleStruct instance;
    instance.i = 5;
    c.RegisterCommand("sampleStruct", instance);
    std::string command;
    while(std::cin >> command && command != "exit") {
        c.CallCommand(command);
    }
    std::cin.get();
}

My noble quest is to get rid of singletons and static classes.

Background:
I have the following structures:

  • Cmd
    Frequently instantiated object, it holds a name of the command (string), and functor to the static method of any class as a pointer.
    It is typically created in main classes such as Input, Console, Render, etc. and refers to methods within the class that it is created in, giving a runtime verbal interface to those methods.
    Cmds also interpret parameters in a form of a string array, where first argument is the name of the Cmd, and all consecutive strings are direct arguments for the static method being invoked. The argument count and argument array are stored in Commander, and changed before each Cmd call.
  • Commander
    Commander is used to interpret string commands (which may come directly, or through Console) and it executes the Cmd which was stored in the buffer as a string (by invoking it's functor).

Problem:
Problem is that I am attempting to get rid of all the static classes (which I now turned into singletons for testing), and I am making the system fully modular and loosely coupled. This in turn prevents me from having static calls which Cmds could point to.

First instinct was to change the functor from a typedef into a template class, which would store an object and method, but it looks very messy and complex, and I personally am not comfortable going from:

Cmd::create("toggleconsole", Console::toggle);

To:

Cmd::create("toggleconsole", new FunctorObject<Console>(&Console::get(), &Console::toggle));

The final Cmd creation looks very obscure and misleading as to who is in charge of the Functor deallocation.

I am also in the process of moving Cmd creation from a static method call, into the Commander class, so it would look like commander.createCmd("command_name", ...); instead of Cmd::create("command_name",...); This is because Commander is no longer going to be static (or singleton), so all commands which it handles must belong to it.

I am, however, at a complete loss as to what my options/alternatives are to register Cmds, and maintain the loose coupling by allowing string commands to be issued to the Commander.

I have considered making each of the main classes derive from a CmdListener class, which would register the object with the Commander upon creation, and then during execution pass a command to all registered objects which overwrote the "onCmd(const Cmd &command)".

This leaves some unanswered questions as well: how will Cmd relay which method of class should be invoked? Keeping pointers wouldn't make sense and would be subject to high level of obscurity (as demonstrated above). Also, I wish to not reinterpret strings in onCmd method for every class that may handle that cmd.

It is a lot of information, but does anybody have any ideas on how to deal with this issue?

Also, all my classes must be aware of Commander and Console objects, which are no longer singleton/static. So far, I have placed them inside a Context object, and am passing it around like a little capsule. Any ideas on how to solve these post-singleton residual problems?

This project is my personal work, and I am planning to use it on my resume - hence, I do not want my potential employers to see any singletons (nor do I want to explain myself as to why, since I can prove to myself they are not truly necessary).

Thanks a ton!

edit: typography.

解决方案

This is a job for the function class. You can find one in Boost, or in TR1 or C++0x. It looks like std::function<void()>, for example. This is often partnered with bind, which you will need if you want to refer to functional objects in a generic way, rather than take them by value, and is also found in Boost, TR1 or C++0x. If you have lambda functions, you can use them too, which is an excellent method.

class Commander {
    std::map<std::string, std::function<void()>> commands;
public:
    void RegisterCommand(std::string name, std::function<void()> cmd) {
        commands[name] = cmd;
    }
    void CallCommand(std::string name) {
        commands[name]();
    }
};
void sampleFunc() {
    std::cout << "sampleFunc()" << std::endl;
}
struct sampleStruct {
    int i;
    void operator()() {
        std::cout << i;
        std::cout << "sampleStruct()() and the value of i is " << i << std::endl;
    }
};

int main() {
    Commander c;
    c.RegisterCommand("sampleFunc", sampleFunc);
    sampleStruct instance;
    instance.i = 5;
    c.RegisterCommand("sampleStruct", instance);
    std::string command;
    while(std::cin >> command && command != "exit") {
        c.CallCommand(command);
    }
    std::cin.get();
}

这篇关于C ++摆脱Singletons:替代函子和静态方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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