不断使新物体正常吗?

时间:2014-02-26 15:45:31

标签: c# single-responsibility-principle

答案:即使将类转换为变量然后调用它们也可行,在这种情况下,它可能是设计糟糕的迹象。更好的设计会产生副作用,不需要不断开始新的类实例。

============

最近我(试图)将SRP应用到我的代码中,将所有职责分成不同的类。它工作得非常好,代码的可维护性和可重用性也增加了很多..但我发现自己经常做new Table.Type("messages").Get(id);之类的事情。

我的大多数类只包含一个方法。仍然......感觉很尴尬。 Guts说这是我可能将它们全部变成静态类的重点。

所以我想我会转向我更有经验的老年人,经常写'新的Class()。方法()'常见吗?或者有更好的方法来处理它吗?

示例代码:

public void AdminCommands(Channel channel, IrcUser user, string message)
{
    var command = message.Split(' ')[0];
    switch (command)
    {
        case "@info":
            GetInfo(channel, message);
            break;
        //----a couple of more commands
    }
}

private void GetInfo(Channel channel, string message)
{
    Match match = Regex.Match(message, "@info (.+)");
    if (match.Success)
    {
        string search = match.Groups[1].Value;
        //Get stored data on the word or sentence, and send the result to chat.
        new CommandInfo().Execute(search);  //<-------------------- over here.
        return;
    }
    Chat.SendAdminMessage("Message not found.");
}
private void EditMessage(Channel channel, string message)
{
    Match match = Regex.Match(message, "@edit (.+?) (.+?) (.+?)=(.+)");
    if (match.Success)
    {
        string type = match.Groups[1].Value;
        string id = match.Groups[2].Value;
        string toReplace = match.Groups[3].Value;
        string replaceWith = match.Groups[4].Value;

        //Gets message of 'type' by 'id', and store it back after editing.
        new CommandEdit().Execute(type, id, toReplace, replaceWith); //<-here.
    }
}

5 个答案:

答案 0 :(得分:3)

您当然可以将CommandEdit和CommandInfo存储为成员变量,然后调用Execute

private CommandInfo mInfo = new CommandInfo();

private void GetInfo(Channel channel, string message)
{
    Match match = Regex.Match(message, "@info (.+)");
    if (match.Success)
    {
        string search = match.Groups[1].Value;
        //Get stored data on the word or sentence, and send the result to chat.
        mInfo.Execute(search);  //<-------------------- over here again.
        return;
    }
    Chat.SendAdminMessage("Message not found.");
}

答案 1 :(得分:2)

从您的示例代码中很难说,但您似乎正在创建具有面向对象的假装外套的过程代码。

我无法从对象模型中了解您的代码。例如,这条线到底是做什么的?

new CommandInfo().Execute(search);

什么是CommandInfo对象?它代表什么? Execute()函数到底是做什么的?我不知道。

对象的全部意义在于它们封装了某种内部状态。如果你经常新事物,那么他们显然没有任何状态。

您的许多代码似乎都在对消息进行操作,那么为什么不在消息类上放置对消息进行操作的方法呢?

Message.GetInfo();
Message.Edit();

等。当我无法弄清楚它所做的代码时,很难建议一个模型,但是你能看到这使代码变得更加明显吗?

答案 2 :(得分:1)

我建议你检查你的对象模型,并验证导致1-1类方法的设计。如果你仍然认为你的建模是可以接受的,我不推荐静态类方法,特别是如果你进行单元测试,这可能会使你的自动化测试最终具有挑战性。

而不是静态,考虑实现一个基本的单元:

public class Work
{
 private static readonly Lazy<Work> _work = new Lazy<Work>(()=> new Work());

 public static Work Instance{get{return _work.Value;}} 

 public void DoWork(){}
}
打电话给它:

Work.Instance.DoWork();

答案 3 :(得分:1)

为什么不为您的类创建一个字段,该字段包含对您不断创建的对象的引用? 像这样你可以避免垃圾收集而你没有创建无用的对象,请参阅:

public class myClass{
...
private ICommandInfo commandInfo= new CommandInfo();

private void GetInfo(Channel channel, string message)
{
    Match match = Regex.Match(message, "@info (.+)");
    if (match.Success)
    {
        string search = match.Groups[1].Value;
        //Get stored data on the word or sentence, and send the result to chat.
        commandInfo.Execute(search);  //<-------------------- no object creation.
        return;
    }
    Chat.SendAdminMessage("Message not found.");
}
...
}

我倾向于使用界面ICommandInfo进一步使用,这将使测试和模拟变得更容易。

答案 4 :(得分:1)

提供某种功能的类也可以被认为是一般意义上的服务。在消费类中注入这些服务是一个好主意(Dependency injectionInversion of control)。

public class Consumer
{
    private ICommandService _commandInfo;

    public Consumer(ICommandService commandInfo)
    {
        _commandInfo = commandInfo;
    }

    public void DoSomething()
    {
        _commandInfo.Execute();
    }
}

此类服务可以在应用程序启动时创建一次。或者实施Singleton pattern

使用注入允许您使用不同的实现,而消费类无需了解它。您甚至可以在制作unit tests时注入虚拟课程(请参阅Mock object)。


在您的示例中,不清楚应用Execute的内容,因为CommandInfo似乎不包含任何数据。您的评论说“......并将结果发送到聊天室”。为什么不使用注入该类的聊天对象?

_chat.Send(search);

这比new CommandInfo().Execute(search);说得更多,而且评论已经过时了。解释代码的注释通常暗示代码有问题。提供背景信息的评论是可以的。