Reputation: 65
I'm trying to implement a factory pattern and I ran into a problem. I try to make my classes simple here. Basically I have a base Packet class (PacketHeader) with some fields and methods. Also I have so many derived packet classes such as: InfoPacket1011, UsagePacket1011, InfoPacket1014, UsagePacket1014 and they all inherit from PacketHeader base class.
As you can see each packet has a version and my goal is to handle this packets based on their versions. So I should have two derived class, one for 1011 and one for 1014.
The base class (which itself is a derived class!) looks like this:
public abstract class PacketHandlerBase : Engine
{
public abstract bool SendInfoPacket(int someInt, string someInput);
public abstract List<???> BuildInfoPacket(string someInput);
public abstract bool SendUsagePacket(int someInt, string someInput);
public abstract List<???> BuildUsagePacket(string someInput);
//...
//...
//...
}
My problem is that for methods such as BuildInfoPacket and BuildUsagePacket I have to return a List of that type. So in the derived classes I could have:
public class PacketHandler1011 : PackerHandlerBase
{
//...
public override bool SendInfoPacket(int someInt, string someInput);
{
// code implementation
// return true or false
}
public override List<InfoPacket1011> BuildInfoPacket(string someInput);
{
// code implementation
// return List<InfoPacket1011>
}
}
public class PacketHandler1014 : PackerHandlerBase
{
//...
public override bool SendInfoPacket(int someInt, string someInput);
{
// code implementation
// return true or false
}
public override List<InfoPacket1014> BuildInfoPacket(string someInput);
{
// code implementation
// return List<InfoPacket1014>
}
}
I don't know what to use in the PacketHandlerBase class to be able to override it in the derived classes. I guess I need generic methods and interface for that, but not sure how to handle that.
[Edit]: I fixed first part of my questions about packet inheritance. Thank you all for your answers, I read them and tell you if they work.
[Answer]: Thank you everyone for your prompt responses. I fixed the problem by passing List and by casting it in the method and in the caller. Well my code was much more complex than what I provided here and I just finished modifying it. I changed the pattern to abstract factory too to fix some other problems.
Any help would be greatly appreciated. Thanks in advance
Upvotes: 4
Views: 6289
Reputation: 6262
How about:
public abstract class PacketHandlerBase<TInfoPacket, TUsagePacket> : Engine
where TInfoPacket : IInfoPacket
where TUsagePacket : IUsagePacket
{
public abstract bool SendInfoPacket(int someInt, string someInput);
public abstract List<TInfoPacket> BuildInfoPacket(string someInput);
public abstract bool SendUsagePacket(int someInt, string someInput);
public abstract List<TUsagePacket > BuildUsagePacket(string someInput);
}
You make sure that your info packet classes implement an IInfoPacket interface. For example:
public InfoPacket1101 : PacketHeader, IInfoPacket
{
...
}
Similarly all the usage packet classes implement IUsagePacket. Then you can write a given version of your packet handler like so:
public class PacketHandler1011 : PackerHandlerBase<InfoPacket1101, UsagePacket1101>
{
...
}
I think this is the preferred solution, as it means you can have stronger guarantees about the returned objects. With only a single base class, as in the currently accepted answer, you can't call any "info packet"-specific methods on objects returned by BuildInfoPacket without casting. Similarly with usage packets. In this solution the IInfoPacket interface could have methods that you are then able to call without casting.
Upvotes: 0
Reputation: 12849
Do not use generics if you don't understand them and are fully aware of their downsides. In this case, you can just return IEnumerable<PacketHeader>
and have the polymorphism resolve rest.
public abstract class PacketHandlerBase : Engine
{
public abstract bool SendInfoPacket(int someInt, string someInput);
public abstract IEnumerable<PacketHeader> BuildInfoPacket(string someInput);
public abstract bool SendUsagePacket(int someInt, string someInput);
public abstract IEnumerable<PacketHeader> BuildUsagePacket(string someInput);
//...
//...
//...
}
public class PacketHandler1011 : PackerHandlerBase
{
//...
public override bool SendInfoPacket(int someInt, string someInput);
{
// code implementation
// return true or false
}
public override IEnumerable<PacketHeader> BuildInfoPacket(string someInput);
{
yield return new InfoPacket1011(..)
// code implementation
// return List<InfoPacket1011>
}
}
Upvotes: 0
Reputation: 13755
all your method in the base class should return InfoPacketBase
as well as creating a base class for packet usage e.g UsagePacketBase
you need to take a look at polymorphism
public abstract class PacketHandlerBase : Engine
{
public abstract bool SendInfoPacket(int someInt, string someInput);
public abstract List<PackeHeader> BuildInfoPacket(string someInput);
public abstract bool SendUsagePacket(int someInt, string someInput);
public abstract List<PackeHeader> BuildUsagePacket(string someInput);
//...
//...
//...
}
Upvotes: 3
Reputation: 3046
Here is an example to use it generic way: Use your entities in type constraint like:
where T : InfoPacketBase
and in derived class method: List<InfoPacket1011>
;
abstract class A
{
public abstract List<T> BuildInfoPacket<T>(string someInput) where T : new();
}
class B : A
{
public override List<T> BuildInfoPacket<T>(string someInput)
{
// code implementation
return new List<T> { new T() };
}
public void Test()
{
BuildInfoPacket<object>("test");
}
}
Upvotes: 0
Reputation: 16878
You are implementing in fact an Abstract Factory pattern where PackerHandlerBase
is an Abstract Factory and it produces/builds an Abstract Product which in your case is an InfoPacket
and UsagePacket
. Concrete Factory is PacketHandler1011
or PacketHandler1014
. And Concrete Product is InfoPacket1011
or InfoPacket1014
and so on.
So it should be:
public abstract class PacketHandlerBase : Engine
{
public abstract bool SendInfoPacket(int someInt, string someInput);
public abstract List<InfoPacket> BuildInfoPacket(string someInput);
public abstract bool SendUsagePacket(int someInt, string someInput);
public abstract List<UsagePacker> BuildUsagePacket(string someInput);
//...
}
public class InfoPacket1014 : InfoPacket
{
///...
}
public class PacketHandler1011 : PackerHandlerBase
{
//...
public override List<InfoPacket> BuildInfoPacket(string someInput);
{
// code implementation
return new List<InfoPacket> { new InfoPacket1011(), ... };
}
}
Upvotes: 3