c#中的友好课程

时间:2010-03-10 15:34:35

标签: c# .net design-patterns oop init

实际上我重构了一部分代码。 我想要做的是用对象“TaskArgument”初始化一个对象“任务”。 我们说“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”是公开的,“Initialize”方法只适用于“任务”。 所以我把类型检查移到另一个地方(将来)。 有没有最佳实践或良好的设计理念。

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

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

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”的给定类型时,哪里是初始化的最佳位置?

请原谅我糟糕的英语知识

问候 莫

5 个答案:

答案 0 :(得分: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;

在您访问对象的多个属性以执行计算时,将该逻辑推入类本身通常是有意义的。

答案 1 :(得分:3)

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

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

答案 2 :(得分: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.
    }
}

答案 3 :(得分: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

答案 4 :(得分: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。