2010-03-10 60 views
4

实际上,我重构了代码的一部分。 我想要做的是用对象“TaskArgument”初始化一个对象“任务”。 让我们说“TaskArgument”是抽象的,“Task”实现了一个方法“OnEnterTask(TaskArgument args)”并且被封闭(对于现有系统的一些特殊行为,它超出了范围)。c中的友好类#

旧代码:

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; 
    } 
    } 
} 

这将是最好的做法避免了类型检测? 我的第一个stupud想到的是:

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”是公众和“初始化”方法只能用“任务”的作品。 所以我将类型检查移到了另一个地方(将来)。 是否有任何最佳实践或良好的设计理念。

...“内部公开”... 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”?

请多原谅我的英语不好知识

问候 月

回答

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;

在那里你在对象上访问多个属性来进行计算,它通常是有意义的这个逻辑推入类本身。

+0

我认为这适用于简单的初始化 – 2010-03-10 16:12:41

+0

@mo,是的我的例子适用于简单的初始化。但它看起来像你在上面创建一个依赖关系网络。我认为让Task类接受TaskArg对象是一种嗅觉,然后在TaskArg上调用它自己传递的初始值(this)。这是一个尴尬的双向依赖。分开你的担忧!如果您需要执行使用Task和TaskArgs状态的计算,则将Task和TaskArgs保留为仅状态类(具有最小的业务逻辑)。然后创建另一个知道两者(但他们不知道它)的类并在那里执行计算。 – manu08 2010-03-10 16:28:38

+0

适合我:)这可能是最干净的方式。 – 2010-03-10 16:41:11

3

听起来像是你想要把每个子类TaskArgument的到该类关联的逻辑。您可以将一个抽象方法添加到名为CalculateTaskArgument,该方法具有特定于子类的计算。这将完全消除你的if语句的需要:

 
public class Task { 
    private int accessMe;

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

然后,你会把乘法或任何适当的东西放到每个子类中。

+0

一个变种的声音很大/ property.but在复杂的初始化的情况下? ComplexTaskArgument可能会为Task上的另一个var/propery提供数据。 我会将这个案例添加到我的问题。 – 2010-03-10 15:50:21

+1

@Mo,那么你需要重新思考你是如何建模的。如果需要计算Task和TaskArgument中需要状态的内容,那么计算需要在知道两者的独立类中进行。 – manu08 2010-03-10 15:56:12

+0

好吧,我认为我配合良好的界面设计。 – 2010-03-10 16:03:22

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. 
    } 
} 
+0

@Ian:你需要修改你的Task.OnEnterTask方法来取ITaskArgument而不是TaskArgument – manu08 2010-03-10 15:54:12

0

您可以创建任务的重载作为一个选项:

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。

+0

也许名字“任务”刺激。 我将它定义为密封。 – 2010-03-10 16:05:27

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