質問

I have an interface that defines one method. This interface has multiple classes that implement that interface differently.

eg:

interface IJob {
  void DoSomething();
}

class SomeJob : IJob{
  public void DoSomething() {
    // Do something ...
  }
}

class AnotherJob : IJob {
  public void DoSomething() {
    // Do something ...
  }
}

...

My factory class will have a bunch of these IF statements

if (some condition)
{
   IJob job = new SomeJob (); 
else
{
   IJob job = new AnotherJob (); 
}

Is there a way to avoid modifying the factory class every time a new condition arises. Can this not be done just by adding a new class that implements IJob ?

Edit: [I am trying to figure out what these guys at the Antiifcampaign are trying to do]

Thanks for your time...

役に立ちましたか?

解決

You have to connect a condition and a decision in some way.

Dictionary<int, Action<IJob>> _methods = new ...

fill the dictionary:

_methods.Add(0, () => {return new SomeJob();});
_methods.Add(1, () => {return new AnotherJob();});

then use it:

public IJob FactoryMethod(int condition)
{
   if(_methods.ContainsKey(condition))
   {
      return _methods[int]();
   }
   return DefaultJob; //or null
}

You need to fill the dictionary on the application startup. From config file, or with some other code. So you don't need to change factory when you have a new condition. Do you like this variant?

他のヒント

Somewhere the decision of what to create has to be made, and it's likely to always involve a conditional statement of some sort.

But you can reduce the need to modify the factory class by using reflection if you can arrange things to follow reasonable naming conventions and/or add reflective supports such as attributes.

See this article for some ideas of how to do this in .Net

You can also base the decision on a map of strings to classnames or even as in another good answer to methods, loaded on application startup, and create the classes at runtime by reflection. Something has to supply the map, but you might be able to move much of the decision to configuration.

It depends on the dynamics of your domain. If you need to evaluete the condition very often you can have some sort of factories for each implementation of IJob, for example SomeJobFactory, AnotherJobFactory, ...

Each will have method MeetsCondition that will evaluate to true if the condition is met and then return the new instance.

public class SomeJobFactory : Factory<IJob>
{
   public bool MeetsCondition() { ... }

   public IJob CreateInstance() { return new SomeJob(); }
}

And in your code

foreach(var jobFactory in allJobFactories)
{
   if(jobFactory.MeetsCondition())
   {
      return jobFactory.CreateInstance();
   }
}

You also use IoC to get all the job factories:

allJobFactories = IoC.ResolveAll<Factory<IJob>>();

When you add new job factory you don't have to modify a single line of code in this example.

If your code is more static you can use the DI and IoC where the object is created once on the startup.

I don't prefer you but you can always use generics:

public IJob GetJob<T>() where : IJob ,new()
{
    IJob job = new T(); 
    return job;

}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top