Reputation: 11073
This question is language-agnostic for OOP languages.
I have two classes: DeviceA
and DeviceB
, which inherit from model class Device
.
I need to implement two services DeviceAService
and DeviceBService
, which inherit from DeviceService
.
My language does not support generics and I need to implement methods with a Device
parameter in DeviceService
, that will be overridden in DeviceAService
and DeviceBService
and implemented differently according to the type of the Device
. Then I want to call these functions from the generic DeviceService
.
What is the best practice to design this? Is the use of if
and check on class type non-avoidable here? Another idea to optimally realize this design?
Upvotes: 1
Views: 85
Reputation: 233197
If I understand the question correctly, you have an abstract base class like this:
public abstract class DeviceService
{
public abstract void DoSomething(Device device);
}
You want to implement DeviceAService
and DeviceBService
so that their behaviour differs based on the type of Device
.
The most object-oriented design is to use polymorphism. Since Device
is already polymorphic, put the behaviour that you want to differ into a polymorphic method, and call it from your service:
public override void DoSomething(Device device)
{
// Perhaps do something first...
device.DoThePolymorphicThing();
// Perhaps do something else after...
}
Implement DoThePolymorphicThing
differently in DeviceA
and DeviceB
.
If you can't change the API of the Device
base class, and you need to also support other implementations than DeviceA
and DeviceB
, you'll probably need to perform a run-time check in DoSomething
:
public override void DoSomething(Device device)
{
if (device is DeviceA)
// Do something...
else if (device is DeviceB)
// Do something else...
else
// remember to handle the case where it's neither A nor B
}
We can call this type of scenario an 'open world', because Device
is open for extensibility.
If, on the other hand, you know that you'll only ever going to have DeviceA
and DeviceB
, the Visitor design pattern is just what you need:
public interface IDeviceVisitor
{
void VisitA(DeviceA device);
void VisitB(DeviceB device);
}
public abstract class Device
{
public abstract void Accept(IDeviceVisitor visitor);
// Other members go here if you need them...
}
public class DeviceA : Device
{
public override void Accept(IDeviceVisitor visitor)
{
visitor.VisitA(this);
}
// Other overrides, if needed, go here...
}
// Define DeviceB in the same way...
You can now implement the service like this:
public override void DoSomething(Device device)
{
// Perhaps do something first...
device.Accept(new MyDeviceVisitor());
// Perhaps do something else after...
}
You can think of this scenario as the 'closed world' scenario, because you can't add a third type of device without changing the Visitor API (and thus breaking existing implementations).
Upvotes: 1