Friendly classes in C #

I'm actually reorganizing a piece of code. what I want to do is initialize the Task object using the TaskArgument object. let s say "TaskArgument" is abstract, and "Task" implements the "OnEnterTask (TaskArgument args)" method and is sealed (for some special behavior of an existing system that is beyond the scope).

old code:

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

What would be the best practice to avoid type checking? my first thought about stupud was:

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

but then my "accessMe" is public, and the "Initialization" method works only with the "Task". so I moved typechecking to another place (in the future). is there any best practice or good design idea.

... the "inner public" ... mmhhmm?

another crazy idea was the inner class, but I don't like it, and it makes such a simple case more complicated or not:

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

where is the best place to initialize when it is based on the given type of "TaskArgument"?

kindly excuse my poor knowledge of english

Hi Mo

+4
source share
5 answers

Use the interface.

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

becomes

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

Then you have classes that implement ITaskArgument and implement a method for each class. In general, when you do something like this:

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

when you access several properties of an object to perform a calculation, it usually makes sense to push this logic to the class itself.

+9
source

It looks like you want to put the logic associated with each subclass of TaskArgument on this class. You can add an abstract method to the TaskArgument called Calculate , which has a specific subclass count. This will completely eliminate the need for your if statements:

 public class Task { private int accessMe; 

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

Then you put the multiplication or something suitable in each subclass.

+3
source

OK, my answer has changed a bit in light of the changing requirements appearing in the comments! (Sheesh, creep area or what ?!)

 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. } } 
+1
source

I would create an open interface that provides only the Intialize method. Do your calculations in your derived classes, for example.

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

example

 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 
+1
source

You can create task overloads as one of the following options:

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

Thus, each type of task deals with an equivalent type of argument. Or you can move the logic to TaskFactory with a static method that returns an int, and there is an argument of type checking there.

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

Your interface implementation will also work; I would not reduce it ... or define an abstract method in Taskargument, which everyone overrides to return a value.

NTN.

0
source

Source: https://habr.com/ru/post/1303685/


All Articles