4

实际上我重构了部分代码。我想做的是用对象“TaskArgument”初始化一个对象“Task”。假设“TaskArgument”是抽象的,“Task”实现了一个方法“OnEnterTask(TaskArgument args)”并且是密封的(对于现有系统的某些特殊行为,超出范围)。

旧代码:

public sealed class Task : SomeSystemBaseTask {
  private int accessMe; 
  private int meToo;

  public void OnEnterTask(TaskArgument args) {
    if (args is SimpleTaskArgument) {
      accessMe = ((SimpleTaskArgument)args).uGotIt;
      meeToo = 0;
    } else if (args is ComplexTaskArgument) {
      accessMe = ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier;
      meToo = ((ComplexTaskArgument)args).multiplier - 1;
    }
  }
}

避免类型检查的最佳做法是什么?我的第一个愚蠢想法是:

public abstract class TaskArgument {
    internal public abstract Initialize(Task args);
}

public class SimpleTaskArgument : TaskArgument {
    public int uGotIt = 10;

    internal public Initialize(Task task){
        task.accessMe = uGotIt;
    }
}

public class ComplexTaskArgument : TaskArgument {
    public int uGotItValue = 10;
    public int multiplier = 10;

    internal public Initialize(Task task){
        task.accessMe = uGotItValue*multiplier;
        task.meToo = multiplier - 1;
    }
}

public sealed class Task : SomeSystemBaseTask {
    public int accessMe;
    public int meToo;

    public void OnEnterTask(TaskArgument args){
        args.Initialize(this);
    }
}

但后来我的“accessMe”是公开的,“初始化”方法只适用于“任务”。所以我将类型检查移到了另一个地方(将来)。是否有任何最佳实践或良好的设计理念。

......“内部公众”......嗯?

另一个疯狂的想法是内部类,但我不喜欢那些,它使这样一个简单的案例更复杂或不:

public abstract class TaskArgument {
    internal public abstract Initialize(ITaskWrapper wrapper);
}

public class SimpleTaskArgument : TaskArgument {
    ...
}

public class ComplexTaskArgument : TaskArgument {
    ...
}

public interface ITaskWrapper {
    public int AccessIt { set; get; } 
    ...  
}

public sealed class Task : SomeSystemBaseTask {
    private int accessMe;
    ...

    class TaskWrapper : ITaskWrapper {
        ...
    }

    public void OnEnterTask(TaskArgument args){
        args.Initialize(new TaskWrapper(this));
    }
}

基于“TaskArgument”的给定类型进行初始化的最佳位置在哪里?

请原谅我糟糕的英语知识

问候莫

4

5 回答 5

9

使用接口。

public void OnEnterTask(TaskArgument args) { 
   if (args is SimpleTaskArgument) { 
      accessMe = ((SimpleTaskArgument)args).uGotIt; 
   } else if (args is ComplexTaskArgument) { 
      accessMe = ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier; 
   } 
} 

变成

public void OnEnterTask(ITaskArgument args) { 
   accessMe = args.GetAccessMe();
} 

然后你让你的类实现 ITaskArgument 并为每个类实现方法。一般来说,当你做这样的事情时:

accessMe = ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier;

在访问对象的多个属性以执行计算的情况下,将逻辑推送到类本身通常是有意义的。

于 2010-03-10T15:42:00.243 回答
3

听起来您想将与 TaskArgument 的每个子类关联的逻辑放到该类上。您可以添加一个抽象方法来TaskArgument调用Calculate具有子类特定计算的方法。这将完全消除对 if 语句的需要:

public class Task {
  private int accessMe; 

public void OnEnterTask(TaskArgument args) { accessMe = args.Calculate(); } }

然后,您可以将乘法或任何适合的内容放入每个子类中。

于 2010-03-10T15:41:35.513 回答
1

好的,根据评论中出现的不断变化的要求改变了我的答案!(Sheesh,范围蠕变还是什么?!)

public class Task
{
    public int Variable1 { get; internal set; }
    public int Variable2 { get; internal set; }

    public void OnEnterTask(ITaskInitializer initializer)
    {
        initializer.Initialize(this);
    }
}

public interface ITaskInitializer
{
    void Initialize(Task task);
}

public class SimpleTaskInitializer : ITaskInitializer
{
    private int uGotIt = 10;

    public void Initialize(Task task)
    {
        task.Variable1 = uGotIt;
    }
}

public class ComplexTaskInitializer : ITaskInitializer
{
    private int uGotIt = 10;
    private int multiplier = 10;

    public void Initialize(Task task)
    {
        task.Variable1 = uGotIt;
        task.Variable2 = uGotIt * multiplier;
        // etc - initialize task however required.
    }
}
于 2010-03-10T15:41:38.853 回答
1

我会创建一个公共接口,它只公开Intialize方法。在派生类中进行计算,例如

public interface ITaskArgument
{
    void Initialize(Task task);
}

public abstract class TaskArgument : ITaskArgument
{
    protected int _value;
    public class TaskArgument(int value)
    {
        _value = value;
    }

    public abstract void Initialize(Task task);
}

public class SimpleTaskArgument : TaskArgument, ITaskArgument
{
    public SimpleTaskArgument(int value)
       : base (value)
    {
    }

    public override void Initialize(Task task)
    {
        task.AccessMe = _value;
    }
}

public class ComplexTaskArgument : TaskArgument, ITaskArgument
{
    private int _multiplier;

    public ComplexTaskArgument(int value, int multiplier)
       : base (value)
    {
         _multiplier = multiplier;
    }

    public override void Initialize(Task task)
    {
        task.AccessMe = _value * _multiplier;
    }
}

public class Task
{
    public Task()
    {
    }

    public int AccessMe { get; set; }

    public void OnEnterTask(ITaskArgument args)
    {                         
        args.Initialize(this);                         
    }  
}

例子

SimpleTaskArgument simpleArgs = new SimpleTaskArgument(10);
ComplexTaskArgument complexArgs = new ComplexTaskArgument(10, 3);
Task task = new Task();
task.OnEnterTask(simpleArgs);
Console.WriteLine(task.AccessMe); // would display 10
task.OnEnterTask(complexArgs);
Console.WriteLine(task.AccessMe); // would display 30
于 2010-03-10T15:51:07.780 回答
0

您可以创建 Task 的重载作为一种选择:

public class SimpleTask : Task
{
   public override void EnterTask(TaskArgument arg)
   {
      var s = (SimpleTaskArgument)arg;
   }
}

因此,每个任务类型都处理一个等效的参数类型。或者,您可以将逻辑移动到具有返回 int 的静态方法的 TaskFactory,并在那里具有类型检查参数。

public static class TaskFactory
{
   public static int GetVal(TaskArgument arg)
   {
      if (args is SimpleTaskArgument) { 
        return ((SimpleTaskArgument)args).uGotIt; 
      } else if (args is ComplexTaskArgument) { 
        return ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier; 
      }
   }
}

您的接口实现也可以工作;我不会打折……或者在 Taskargument 中定义一个抽象方法,每个方法都会覆盖以返回值。

HTH。

于 2010-03-10T15:42:26.080 回答