Reputation: 1189
I have two classes, Server and Client. Server needs to instantiate Client in multiple threads and Client has a virtual member that needs to provide a custom implementation. My question is. Should the Client class be a nested class of the Server class or should I use an Interface and Dependency Injection to get the custom implementation into the Server class. Now the Client class also has many private methods that provide some standard logic that shouldn't be changed.
public class Server
{
public void DoWork()
{
for (var i = 0;i < 10; i++)
{
Client client = new Client();
client.Process(i);
}
}
}
public class Client
{
private void doSomething()
{
...
}
// Needs to be overridden and provide custom logic
public virtual string Process(int i)
{
return i.ToString();
}
}
Working example:
public interface IClient
{
string Process(string message);
}
public abstract class Client : IClient
{
public virtual string Process(string message)
{
return message;
}
}
public class CustomClient : Client
{
public CustomClient() { }
public override string Process(string message)
{
return string.Format("Custom Client:{0}", message);
}
}
public class Server
{
private Func<IClient> createClient;
public Server() { }
public Server(Func<IClient> client)
{
createClient = client;
}
public void DoWork()
{
for (var i = 0; i < 10; i++)
{
IClient = client = createClient();
client.Process(string.Format("Client #{0}", i));
}
}
}
Test Program...you would step through to see it hit the CustomClient
class Program
{
static void Main(string[] args)
{
Func<CustomClient> factory = () => new CustomClient();
var server = new Server(factory);
server.DoWork();
}
}
Upvotes: 1
Views: 451
Reputation: 109762
If the Server needs to create a Client, I'd pass a factory method to the Server for it to use. So I'd go for dependency injection.
For example: You could pass to the Server
constructor a Func<IClient>
and assign it to a private field called, say, createClient
and then instead of
Client client = new Client();
use
IClient client = createClient();
That way you can completely decouple the server and the client.
I prefer using a simple Func
delegate rather than a full factory class, since that is (a) easier to use and (b) more loosely coupled.
Upvotes: 1
Reputation: 48279
The question whether a dependency should be injected or fixed has a simple answer - a class providing logic which is a subject of change is a candidate to be injected. On the other hand, if you don't plan to change the logic, you code against fixed types, as you do with most base class libraries.
What you describe sounds like a scenario for DI - if you allow to override the client class then you assume that changes are possible. DI is one of most obvious ways to handle the dependency and the change in the same time.
Upvotes: 1