java界面设计:如何处理有状态处理

时间:2020-12-15 15:34:02

I'm having trouble designing a good architecture for a particular portion of my application, especially where maintaining state is involved.

我在为应用程序的特定部分设计一个好的架构时遇到了麻烦,特别是在涉及维护状态的情况下。

I have a group of parsing operations:

我有一组解析操作:

My class Reader reads in a block of data into a buffer and handles the overall control flow. My class Parser takes the block of data in the buffer and a ParsedDataHandler, and divides it up into smaller chunks for the ParsedDataHandler to manage.

我的类Reader将一个数据块读入缓冲区并处理整个控制流程。我的类Parser获取缓冲区中的数据块和ParsedDataHandler,并将其分成较小的块以供ParsedDataHandler管理。

ParsedDataHandler is an interface that I am trying to design; I think I want to do something like this ("BlockInfo" represents some data structure containing various bits of state that will include a ByteBuffer holding the entire block of raw data. "ChunkMetadata" represents information including the position of each chunk within the block, and any other information the Parser has determined about the chunk)

ParsedDataHandler是我试图设计的接口;我想我想做这样的事情(“BlockInfo”代表一些包含各种状态位的数据结构,它将包含一个包含整个原始数据块的ByteBuffer。“ChunkMetadata”表示包括块内每个块的位置的信息,和Parser确定的关于块的任何其他信息)

interface ParsedDataHandler
{
    void beginBlock(BlockInfo bi);
    void handleParsedData(BlockInfo bi, ChunkMetadata m);
    void endBlock(BlockInfo bi);
}

so Reader will call ParsedDataHandler.beginBlock() to let it set up any state at the beginning of a block, and is committed to leaving a designated portion (probably all) of the BlockInfo constant until it makes a matching call to ParsedDataHandler.endBlock() -- afterwards it might reuse the data buffer for the next block. Parser runs through the data block and splits it into chunks according to a predefined data protocol, and will call ParsedDataHandler.handleParsedData() multiple times, once for each chunk. One reason for the contract to include a buffer that remains fixed, is so that ParsedDataHandler can copy the whole block of data at the beginning or end, and doesn't have to reassemble the chunks into the one block when they were there together all the time.

因此,Reader会调用ParsedDataHandler.beginBlock()让它在块的开头设置任何状态,并且承诺保留BlockInfo常量的指定部分(可能全部),直到它对ParsedDataHandler.endBlock进行匹配调用( ) - 之后它可能会为下一个块重用数据缓冲区。解析器遍历数据块并根据预定义的数据协议将其拆分为块,并将多次调用ParsedDataHandler.handleParsedData(),每个块一次。合同包含一个保持固定的缓冲区的一个原因是,ParsedDataHandler可以在开头或结尾复制整个数据块,并且当它们在一起时不必将块重新组装到一个块中时间。

So there's a division of responsibility:

所以责任分工:

  • Reader is just responsible for managing the overall routine and reading in the data, it couldn't care less about anything else.
  • 读者只负责管理整个例程和读取数据,它不会关心其他任何事情。

  • Parser is the thing that splits the data block into chunks and it couldn't care less about what to do with them or how the data got there
  • 解析器是将数据块拆分成块的东西,它不关心如何处理它们或数据如何到达那里

  • ParsedDataHandler is the interface I'm trying to design so that concrete classes can implement it and work correctly, without Reader or Parser caring what it does, or without it caring about how to divide up the block into chunks or where the data came from.
  • ParsedDataHandler是我试图设计的接口,因此具体的类可以实现它并正常工作,没有Reader或Parser关心它的功能,或者没有它关心如何将块分成块或数据来自何处。

My question is, should the burden on maintaining any state be on the class implementing ParsedDataHandler and kept out of BlockInfo? And if the semantics of my interface include the fact that the raw data block in BlockInfo will not change between calls of beginBlock() and endBlock(), should I then only pass it in to beginBlock() and not to the other calls? or is it okay to send it along for convenience's sake?

我的问题是,维护任何状态的负担是否应该在实现ParsedDataHandler并且不在BlockInfo之外的类上?如果我的接口的语义包括BlockInfo中的原始数据块在beginBlock()和endBlock()的调用之间不会改变的事实,那么我应该只将它传递给beginBlock()而不是其他调用吗?或者为了方便起见可以发送它吗?

Is there a better design pattern to handle a situation like this?

是否有更好的设计模式来处理这种情况?

1 个解决方案

#1


First your implementation is pretty close to the the classic example of a State Pattern. The only issue I see is the role of BlockInfo.

首先,您的实现非常接近状态模式的经典示例。我看到的唯一问题是BlockInfo的作用。

If BlockInfo is being changed in between the steps then your implementation is what you need to do. Look at the Wikipedia article I referenced. Point is being changed between Mousedown, MouseMove, and MouseUp so it has to be a parameter of a Abstract Tool.

如果在步骤之间更改BlockInfo,那么您的实现就是您需要做的。看看我引用的*文章。在Mousedown,MouseMove和MouseUp之间更改点,因此它必须是抽象工具的参数。

If BlockInfo is not being changed between the steps then you have several things to consider.

如果在步骤之间没有更改BlockInfo,那么您需要考虑几件事情。

If the class implementing ParsedDataHandler is initializing any part of the BlockInfo structure then I would separate that out and make it a private member of the class and just have BlockInfo pass in the initialization data that is external to the parsing process.

如果实现ParsedDataHandler的类正在初始化BlockInfo结构的任何部分,那么我将其分离并使其成为该类的私有成员,并且只允许BlockInfo传递解析过程外部的初始化数据。

If BlockInfo is being modified by BeginBlock and passed to the subsequent routines then you should clone BlockInfo, store it internally in the class implementing ParsedDataHandler. Then eliminate it from the parameter list.

如果BeginBlock正在修改BlockInfo并将其传递给后续例程,那么您应该克隆BlockInfo,将其内部存储在实现ParsedDataHandler的类中。然后从参数列表中删除它。

If you need BlockInfo afterward I would make a readonly property that return the internal BlockInfo.

如果您之后需要BlockInfo,我将创建一个返回内部BlockInfo的readonly属性。

Based on your question my guess you should pass BlockInfo into BeginBlock and store it internally. Eliminate it from the parameters from the other methods then add the readonly property if you need to retrieve it.

基于您的问题,我猜您应该将BlockInfo传递给BeginBlock并在内部存储它。从其他方法的参数中消除它,然后添加readonly属性,如果您需要检索它。

#1


First your implementation is pretty close to the the classic example of a State Pattern. The only issue I see is the role of BlockInfo.

首先,您的实现非常接近状态模式的经典示例。我看到的唯一问题是BlockInfo的作用。

If BlockInfo is being changed in between the steps then your implementation is what you need to do. Look at the Wikipedia article I referenced. Point is being changed between Mousedown, MouseMove, and MouseUp so it has to be a parameter of a Abstract Tool.

如果在步骤之间更改BlockInfo,那么您的实现就是您需要做的。看看我引用的*文章。在Mousedown,MouseMove和MouseUp之间更改点,因此它必须是抽象工具的参数。

If BlockInfo is not being changed between the steps then you have several things to consider.

如果在步骤之间没有更改BlockInfo,那么您需要考虑几件事情。

If the class implementing ParsedDataHandler is initializing any part of the BlockInfo structure then I would separate that out and make it a private member of the class and just have BlockInfo pass in the initialization data that is external to the parsing process.

如果实现ParsedDataHandler的类正在初始化BlockInfo结构的任何部分,那么我将其分离并使其成为该类的私有成员,并且只允许BlockInfo传递解析过程外部的初始化数据。

If BlockInfo is being modified by BeginBlock and passed to the subsequent routines then you should clone BlockInfo, store it internally in the class implementing ParsedDataHandler. Then eliminate it from the parameter list.

如果BeginBlock正在修改BlockInfo并将其传递给后续例程,那么您应该克隆BlockInfo,将其内部存储在实现ParsedDataHandler的类中。然后从参数列表中删除它。

If you need BlockInfo afterward I would make a readonly property that return the internal BlockInfo.

如果您之后需要BlockInfo,我将创建一个返回内部BlockInfo的readonly属性。

Based on your question my guess you should pass BlockInfo into BeginBlock and store it internally. Eliminate it from the parameters from the other methods then add the readonly property if you need to retrieve it.

基于您的问题,我猜您应该将BlockInfo传递给BeginBlock并在内部存储它。从其他方法的参数中消除它,然后添加readonly属性,如果您需要检索它。