我应该在这里使用哪种设计模式

发布于 2024-10-08 18:30:38 字数 1062 浏览 1 评论 0原文

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

我有不同类型的数据包,例如 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 是在抽象类 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");

如果我必须检查传递的数据类型是否正确,我最终会再次得到大量愚蠢的代码。 如何才能既减少重复代码又摆脱上述问题呢?

For learning purposes I am writing a socket based client/server application. I have designed a custom protocol to ensure I can process my packets correctly. While inspecting some older parts of code today I realized that my way of creating my data packets contains much redundant code.

I have different types of packets, e.g. ImagePacket, MessagePacket etc. The creation of all types differs only in minor stuff, the header and delimiter creation for example is the same.

To improve this, i came up with a solution like this (simplified):

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);

The AddData method is implemented as abstract method and overridden in the concrete classes whereas AddHeader and AddDelimiter are defined in the abstract class Packet itself.

This works fine and I don't have as much duplicated code as before but I am not happy with
passing an object to AddData because it is not made clear that i must not give a string to the ImagePacket constructor.

// 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");

If I had to to implement a check for the correct data type being passed I would end up with tons of stupid code again.
How can I achieve the reduction of duplicated code but also get rid of the problem mentioned above?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

穿透光 2024-10-15 18:30:38

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

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() - 这将使您的代码

This sounds like you need to use the factory pattern

Packet MyPacket = MyPacketFactory.CreatePacket(Data)

MyFactory.CreatePacket would then return an IPacket

Update: As per the comment below, I should've been clearer. Your factory can have a number of overloaded CreatePacket() methods which take different data types...

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

and if you have multiple types of packet which contain just String (Eg Message packet, Status packet or similar) You could create an Enum indicating which string packet is desired...

IPacket CreatePacket(String Data, StringPacketTypesEnum PacketType) {}

Inside you packet factory, you can have common functions which deal with all the duplicated code - eg AddDelimiter() - This will keep your code DRY

在风中等你 2024-10-15 18:30:38

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

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

Ruby on Rails uses Validations to solve this.

If your addData() function called validate() on the input you should just have to override validate() in each subclass.

治碍 2024-10-15 18:30:38

我会使用返回接口的工厂模式。

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

I would go to factory pattern that returns a interface.

Beside that, you don't need to use ref for reference types.

彼岸花ソ最美的依靠 2024-10-15 18:30:38

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

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

这将在复制时检查数据是否是图像。当然,如果您确实必须传递 object 类型,则这可能不起作用。

I think your current solution is OK. You just need to narrow down the type of data passed to the ImagePacket constructor to Image type. For example:

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

This will check that data is an image at copile-time. Of course, this might not work if you really have to pass an object type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文