I had a loop through object Process, each process instance can be of a different
ID: 639818 • Letter: I
Question
I had a loop through object Process, each process instance can be of a different type, derived from Process base class (e.g.: Process1, Process2,...). Each derived type of Process has different properties. For instance: some Processes are indexable, this is notified by IsIndexable flag. When a Process is indexable has some additional properties (for instance: AccessDate) that non-indexable process doesn't have. Now I have to cycle on each Process in request.Process (remember indexable Processes are different from others)
foreach (Process process in request.Processes)
{
if(process.getType().Name.Equals("Process1")) // indexable process
{
((Process1)process).Name = "aName";
((Process1)process).AccessDate = DateTime.Now;
}
else if(process.getType().Name.Equals("Process2")) // non indexable process
{
((Process2)process).Name = "anotherNane";
//compile error - AccessDate don't exist for type Process2
//((Process2)process).AccessDate = DateTime.Now;
}
}
Since I hate that cascading if I have rewritten using interface:
IProcessable processableImpl = // some Unity stuff based on request type
foreach (Process process in request.Processes)
{
processableImpl.fillTheRightProperties(process);
}
processableImpl is injected in a different manner based on the request.Type. At this point fillTherRightProperties method will do the work for me on the current process.
public interface IProcessable
{
void fillTheRightProperties(Process process);
}
public class IndexableProcess : IProcessable
{
void fillTheRightProperties(Process process){
Process1 process1 = process as Process1;
if(process1==null) throw MyException("Process1 expected");
process1.Name = "aName";
process1.AccessDate = DateTime.Now;
}
}
public class NonIndexableProcess : IProcessable
{
void fillTheRightProperties(Process process){
Process2 process2 = process as Process2;
if(process2==null) throw MyException("Process2 expected");
process2.Name = "aName";
}
}
This is more beautiful than a cascading if but I feel still not as beautiful as it could be. I feel a violation of responsability, since the concrete class edit process property elsewhere, and I'm afraid to read this code a week after.
Explanation / Answer
Below is an example using an interface and two implementations in a console application:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var processes = new List<IProcessable>();
processes.Add(new Process1());
processes.Add(new Process2());
foreach (IProcessable item in processes)
{
item.FillTheRightProperties();
}
Console.WriteLine();
Console.WriteLine("Press Enter/Return to exit...");
Console.ReadLine();
}
}
interface IProcessable
{
void FillTheRightProperties();
}
class Process1 : IProcessable
{
public string Name { get; set; }
public DateTime AccessDate { get; set; }
public void FillTheRightProperties()
{
this.Name = "aName";
this.AccessDate = DateTime.Now;
Console.WriteLine("Properties filled: {0}, {1}", this.Name, this.AccessDate);
}
}
class Process2 : IProcessable
{
public string Name { get; set; }
public void FillTheRightProperties()
{
this.Name = "aName";
Console.WriteLine("Properties filled: {0}", this.Name);
}
}
}
The key line is in the foreach where we use the interface rather than casting to a concrete class.
To map this to your example request.Processes would be a List<IProcessItem> meaning we can guarantee that the DoSomething() method exists, and there is no need to cast to a concrete class.
The base class can also be used, but it's purpose would be to hold common code only.
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.