Skip to main content
Rewrote answer cause it was not that great
Source Link
JamesFaix
  • 272
  • 2
  • 10

I would suggest one of twoseveral things.

The untyped ugly way:

Change If you want to maintain encapsulation, so that the signature IWorker.DoWorkcallsites don't have to string IWorker.DoWork(object[] args)know anything about the inner workings of the workers or the worker factory, then you'll need to change the interface to have the extra parameter.

This will allow total flexibility in arguments and future extension The parameter can have a default value, at the cost of type safetyso that some callsites can still just use 2 parameters. This will probably take less effort to implement, but will be a pain to debugrequire that any consuming libraries are recompiled.

The cleaner generic way:

Create a series of interfaces IWorker<T>, IWorker<T1, T2>The other option I would recommend against, as it breaks encapsulation and is just generally bad OOP. This also requires that you can at least modify all the callsites for IWorker<T1, T2, T3>ConcreteWorkerB, etc. in You could create a similar fashion toclass that implements the Func<T>IWorker interface, but also has a Func<T1, T2>DoWork etc. delegatesmethod with an extra parameter. In your case,Then in your existing sites usingcallsites attempt to cast the ConcreteWorkerAIWorker type would usewith IWorker<int,var List<int>>workerB = myIWorker as ConcreteWorkerB; and the ConcreteWorkerB sites wouldthen use the three parameter IWorker<int, List<int>, string>DoWork. The instances of the versions with less arguments could always be converted to versions with more arguments by using a default argument for on the extra parametersconcrete type. So to continue to use the workers with different argument lists interchangeably, you would have to make the factory create workers with 3 arguments Again, and using default values where needed.

I don't think there is anyway you can practically make this extension without breaking all existing callsitesis a bad idea, but the changeit is something you make now can provide a path for extensibility in the futurecould do.

I would suggest one of two things.

The untyped ugly way:

Change the signature IWorker.DoWork to string IWorker.DoWork(object[] args).

This will allow total flexibility in arguments and future extension, at the cost of type safety. This will probably take less effort to implement, but will be a pain to debug.

The cleaner generic way:

Create a series of interfaces IWorker<T>, IWorker<T1, T2>, IWorker<T1, T2, T3>, etc. in a similar fashion to the Func<T>, Func<T1, T2> etc. delegates. In your case, your existing sites using the ConcreteWorkerA type would use IWorker<int, List<int>> and the ConcreteWorkerB sites would use IWorker<int, List<int>, string>. The instances of the versions with less arguments could always be converted to versions with more arguments by using a default argument for the extra parameters. So to continue to use the workers with different argument lists interchangeably, you would have to make the factory create workers with 3 arguments, and using default values where needed.

I don't think there is anyway you can practically make this extension without breaking all existing callsites, but the change you make now can provide a path for extensibility in the future.

I would suggest one of several things.

If you want to maintain encapsulation, so that the callsites don't have to know anything about the inner workings of the workers or the worker factory, then you'll need to change the interface to have the extra parameter. The parameter can have a default value, so that some callsites can still just use 2 parameters. This will require that any consuming libraries are recompiled.

The other option I would recommend against, as it breaks encapsulation and is just generally bad OOP. This also requires that you can at least modify all the callsites for ConcreteWorkerB. You could create a class that implements the IWorker interface, but also has a DoWork method with an extra parameter. Then in your callsites attempt to cast the IWorker with var workerB = myIWorker as ConcreteWorkerB; and then use the three parameter DoWork on the concrete type. Again, this is a bad idea, but it is something you could do.

Source Link
JamesFaix
  • 272
  • 2
  • 10

I would suggest one of two things.

The untyped ugly way:

Change the signature IWorker.DoWork to string IWorker.DoWork(object[] args).

This will allow total flexibility in arguments and future extension, at the cost of type safety. This will probably take less effort to implement, but will be a pain to debug.

The cleaner generic way:

Create a series of interfaces IWorker<T>, IWorker<T1, T2>, IWorker<T1, T2, T3>, etc. in a similar fashion to the Func<T>, Func<T1, T2> etc. delegates. In your case, your existing sites using the ConcreteWorkerA type would use IWorker<int, List<int>> and the ConcreteWorkerB sites would use IWorker<int, List<int>, string>. The instances of the versions with less arguments could always be converted to versions with more arguments by using a default argument for the extra parameters. So to continue to use the workers with different argument lists interchangeably, you would have to make the factory create workers with 3 arguments, and using default values where needed.

I don't think there is anyway you can practically make this extension without breaking all existing callsites, but the change you make now can provide a path for extensibility in the future.