Let's say there are classes D1, D2, etc. describing different types of an abstract class D.
Let's say there are SenderReceiver classes describing different ways of communicating for each D1, D2, etc.:
abstract class SenderReceiver {
abstract void Setup();
abstract void SendA();
public void M1() { /* Common code */ }
...
public void MN() { /* Common code */ }
}
abstract class SenderReceiverPlus : SenderReceiver {
abstract void SendB();
}
class SenderReceiverPlusTcp : SenderReceiverPlus {
override void Setup() { /* BeginConnect code */ }
}
class SenderReceiverTcp : SenderReceiver {
override void Setup() { /* Same code as above (vomit) */ }
}
class SenderReceiverPlusTcpD1 : SenderReceiverPlusTcp {
override void SendA() { /* Code */ }
override void SendB() { /* Code */ }
}
class SenderReceiverTcpD2 : SenderReceiverTcp {
override void SendA() { /* Code */ }
}
class SenderReceiverPlusUdp : SenderReceiverPlus {
override void Setup() { /* Socket bind code */ }
}
class SenderReceiverUdp : SenderReceiver {
override void Setup() { /* Same code as above (vomit) */ }
}
class SenderReceiverPlusUdpD3 : SenderReceiverPlusUdp {
override void SendA() { /* Code */ }
override void SendB() { /* Code */ }
}
class SenderReceiverUdpD4 : SenderReceiverUdp {
override void SendA() { /* Code */ }
}
abstract class D {
SenderReceiver S;
abstract void DoThing();
}
class D1 : D {
D1 () { S = new SenderReceiverPlusTcpD1(); }
override void DoThing() { S.SendA(); S.SendB(); S.M1(); }
}
class D2 : D {
D2 () { S = new SenderReceiverTcpD2(); }
override void DoThing() { S.SendA(); S.M1(); }
}
class D3 : D {
D1 () { S = new SenderReceiverPlusUdpD3(); }
override void DoThing() { S.SendA(); S.SendB(); S.M1(); }
}
class D4 : D {
D2 () { S = new SenderReceiverUdpD4(); }
override void DoThing() { S.SendA(); S.M1(); }
}
And there is a class with a list of D objects:
class Controller {
List<D> ds;
public Controller() {
ds = new List<D>(new [] {new D1(), new D2(), new D3(), new D4()});
}
public DoAllThings() {
foreach (D d in ds) {
d.DoThing();
}
}
}
This does not work because (for one) D1's reference to S references a SenderReceiver and so SendB() is not assuredly there. Also, it's gross and there's duplicated code in the different Tcp and Udp types.
I've considered empty virtual methods in the base class, casting S to the correct type in D1 and D2, and not having S in the D class. None of these are particularly satisfying.
Is there a better way to do this?
EDIT:
Updated code to show attempts in current code at flexibility for Udp/Tcp protocols.