2010-12-19 133 views
2

为了学习的目的,我正在编写一个基于套接字的客户端/服务器应用程序。我设计了一个自定义协议,以确保我可以正确处理我的数据包。今天在检查一些较旧的代码部分时,我意识到我创建数据包的方式包含很多冗余代码。我应该在这里使用哪种设计模式

我有不同类型的数据包,例如, ImagePacket,MessagePacket等。所有类型的创建只有次要的东西不同,例如头和分隔符创建是相同的。

为了改善这一点,我提出了这样的解决方案(简化的):

abstract class Packet 
{ 
public Packet(object o) 
{ 
MemoryStream memoryStream = new MemoryStream();   

AddHeader(ref memoryStream); 
AddData(ref memoryStream, obj); 
AddDelimiter(ref memoryStream); 
_packetBytes = memoryStream.ToArray(); 

memoryStream.Close(); 
} 
protected abstract void AddData(ref MemoryStream ms, object obj); 

的AddData方法被实现为抽象的方法,并在具体的类,而的AddHeader和AddDelimiter重写在抽象的定义class Packet本身。

这工作正常,我没有像以前那样重复的代码,但我不高兴 传递一个对象到AddData,因为它没有明确表示我不能给字符串ImagePacket构造函数。

// correct 
Packet myMsgPacket = new MessagePacket("hello world"); 
Packet myImagePacket = new ImagePacket(image); 
// wrong, but will be compiled :(
Packet myChaosPacket = new ImagePacket("muaha you're doomed"); 

如果我不得不实施检查传递正确的数据类型,我会再次愚蠢的代码吨。 我该如何实现重复代码的减少,但也摆脱了上述问题?

回答

3

这听起来像你需要使用工厂模式则

Packet MyPacket = MyPacketFactory.CreatePacket(Data) 

MyFactory.CreatePacket将返回IPacket

更新:按下面的评论,我应该已经明确。您的工厂可以有若干个重载CreatePacket(),它采取不同的数据类型的方法...

IPacket CreatePacket(Image Data) {} 
IPacket CreatePacket(String Data) {} 
IPacket CreatePacket(Exception Data) {} 

,如果您有多种类型的数据包包含只是字符串(例如,消息包,状态包或类似)你可以创建一个枚举,指示串包所需...

IPacket CreatePacket(String Data, StringPacketTypesEnum PacketType) {} 

里面你包的工厂,你可以有哪些处理所有的重复代码常用功能 - 例如AddDelimiter() - 这会使你的代码DRY

+0

问题是关于什么数据参数可以。用户想知道数据是字符串还是图像。 – 2010-12-19 04:04:37

+0

也许我应该更清楚,但当然,它可以 - 我会有一些重载采取不同的数据类型,可能还有一个额外的'enum'类型的字符串数据 – Basic 2010-12-19 14:18:19

0

Ruby on Rails使用验证来解决这个问题。

如果您的addData()函数在输入上调用validate(),您应该只需要在每个子类中重写validate()。

0

我会去工厂模式,返回一个接口。

除此之外,您不需要使用ref作为参考类型。

0

我认为你目前的解决方案是可以的。您只需要将传递给构造函数ImagePacket的数据类型缩小为Image类型。例如:

class ImagePacket : Packet{ 
    public ImagePacket(Image img) : base(img){} 
} 

这将检查数据是否为copile-time时的图像。当然,如果你真的必须通过object类型,这可能不起作用。

相关问题