如何将聊天命令实现为单独的类?

时间:2019-01-11 03:14:47

标签: c# class inheritance command derived-class

我目前正在Twitch频道的聊天机器人上工作,并且希望将所有命令作为程序中的单独类,以便只需要添加或删除单个类即可添加或删除命令。

我已经在互联网上搜索了很长时间,但从未遇到合适的设计。以下是我认为的外观,但找不到正确的语法。

class Command()
{
    string keyword;
    int globalCooldown;
    List<string> args;
}

class DoStuffA : Command(List<string> _args)
{
    keyword = "pleasedostuffa";
    globalCooldown = 2;
    args = _args;

    DoStuff(List<string> args)
    {
      //doing stuff A here with all the logic and so on
    }
}
class DoStuffB : Command(List<string> _args)
{
    keyword = "pleasedostuffb";
    globalCooldown = 8;
    args = _args;

    DoStuff(List<string> args)
    {
      //doing stuff B here with all the logic and so on
    }
}

我之所以需要它,是因为我想将所有可能的命令存储在List<Commands>中,并且当出现新的聊天消息时,使用chat命令搜索该列表中的哪个对象与keyword匹配,然后执行适当的功能。例如,如果有人发布!pleasedostuffa,我将执行

foreach (Command c in commands)//commands is List<Command>
{
    if(c.keyword==receivedCommand.command)//.command is string
    {
        c.DoStuff(receivedCommand.argsAsList)//.argsAsList is List<string>
    }
}

我希望我能正确地解释这一点,并且真的很希望至少对如何实现这一点有所了解。

提前谢谢!

1 个答案:

答案 0 :(得分:0)

您几乎可以正确设置方法,尽管还需要进行其他一些更改。您需要让基类将DoStuff()公开为虚拟方法。试试这个:

public abstract class Command
{
    public string keyword;
    public int globalCooldown;
    //List<string> args;

    public abstract void DoStuff(List<string> args);
}

public class DoStuffA : Command
{
    //public string keyword = "pleasedostuffa";
    //public int globalCooldown = 2;
    //args = _args;

    public DoStuffA()
    {
        keyword = "pleasedostuffa";
        globalCooldown = 2;
    }

    public override void DoStuff(List<string> args)
    {
      //doing stuff A here with all the logic and so on
    }
}

public class DoStuffB : Command
{
    //public string keyword = "pleasedostuffb";
    //public int globalCooldown = 8;
    // args = _args;

    public DoStuffB()
    {
        keyword = "pleasedostuffb";
        globalCooldown = 8;
    }

    public override void DoStuff(List<string> args)
    {
      //doing stuff B here with all the logic and so on
    }
}

因此,有几点注意事项。

方法继承

在这里,我将基类设为抽象,只是为了强制每个子命令都实现抽象功能DoStuff()。毕竟,您将如何处理基类的实例?它不会做任何事情,因为您没有实际的实现。因此,抽象既可以避免意外实例化Command本身,又可以确保子类型实现者做正确的事情。

第二,在子类级别,您需要override在基类上的方法。这样可以确保调用((Command)doStuffB).DoStuff()的任何对象都能正确实现该函数。

现在,您在Command上具有DoStuff()方法,您的foreach循环应可以正常工作。您可以在基类上使用该方法,因此可以在不强制转换的情况下运行子级的虚拟替代。

基类成员访问权限

您要在此处声明的字段keywordglobalCooldown并不是人们通常会公开这样的信息的方式,但是在我们开始之前,我将先解释更多从继承的类访问基类成员的基本原理。

这两个字段需要标记为public(并指定适当的类型),以便可以在类外部(在您的foreach中)使用它们。 public关键字称为可访问性修饰符,还有其他一些可访问性选项,但就您而言,只有public可能会做您想要的事情。

如您所见,我已经注释掉了子类中的字段。如果在此处声明它们,它们将隐藏(但不会覆盖)基类上具有相同名称的成员。字段没有等效的virtualabstract,因此您需要另一种策略。在这里,我们将这些字段的原始声明保留在基类上,以便拥有任何命令类型的任何人都可以使用它们。但是,我们无需在子类级别上重新声明它们,而只是在子类的构造函数中设置基类成员的值。

请注意,为清楚起见,您可以使用base.keyword = "etc";来明确指定要在基类上设置成员。

通过属性公开内部值

正如我指出的那样,这是可行的,但这并不是大多数人公开keywordglobalCooldown值的方式。为此,通常应使用属性。这使您可以存储和公开值,而不必冒险让某人(有意或无意)更改值。在这种情况下,您需要这样声明属性:

public string Keyword // properties start with a capital letter by convention
{
    get; // The get accessor is public, same as the overall property
    protected set; // the set accessor is protected
}

protected集访问器意味着仍可以由子类(而不是其他任何人)来设置。这可能就是您想要的。因此,现在,在子构造函数中,您可以设置base.Keyword = "whatever";,并且foreach代码可以引用但不能覆盖该值。您可以通过类似的方式声明GlobalCooldown。