实际上我重构了一部分代码。 我想要做的是用对象“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”的给定类型时,哪里是初始化的最佳位置?
请原谅我糟糕的英语知识
问候 莫
答案 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。