我在为应用程序的特定部分设计一个好的架构时遇到了麻烦,特别是在涉及维护状态的情况下。
我有一组解析操作:
我的班级Reader
将一个数据块读入一个缓冲区并处理整个控制流程。
我的班级Parser
获取缓冲区中的数据块和ParsedDataHandler
,并将其划分为较小的块,以便ParsedDataHandler
进行管理。
ParsedDataHandler
是我试图设计的界面;我想我想做这样的事情(“BlockInfo”代表一些包含各种状态位的数据结构,其中包含一个包含整个原始数据块的ByteBuffer。“ChunkMetadata”表示包括块内每个块的位置的信息,以及Parser
已确定的关于块的任何其他信息
interface ParsedDataHandler
{
void beginBlock(BlockInfo bi);
void handleParsedData(BlockInfo bi, ChunkMetadata m);
void endBlock(BlockInfo bi);
}
所以Reader
将调用ParsedDataHandler.beginBlock()
让它在块的开头设置任何状态,并且承诺保留BlockInfo常量的指定部分(可能全部),直到它成为匹配对ParsedDataHandler.endBlock()
的调用 - 之后它可能会为下一个块重用数据缓冲区。 Parser
运行数据块并根据预定义的数据协议将其拆分为块,并且将针对每个块多次调用ParsedDataHandler.handleParsedData()
。合同包含一个保持固定的缓冲区的一个原因是ParsedDataHandler
可以在开头或结尾复制整个数据块,并且当它们是时,不必将块重新组装到一个块中。一直在一起。
所以责任分工:
Reader
负责管理整个例行程序和读取数据,它不会关心其他任何事情。 Parser
是将数据块拆分成块的东西,它不关心如何处理它们或数据如何到达那里ParsedDataHandler
是我正在设计的界面,以便具体的类可以实现它并正常工作,没有Reader
或Parser
关心它的作用,或者没有关心它如何将块分成块或数据来自何处。我的问题是,维护任何状态的负担是否应该在实现ParsedDataHandler
的类上并且不在BlockInfo之外?如果我的接口的语义包括BlockInfo中的原始数据块在beginBlock()和endBlock()的调用之间不会改变的事实,那么我应该只将它传递给beginBlock()而不是其他调用吗?或者为了方便起见可以发送它吗?
是否有更好的设计模式来处理这种情况?
答案 0 :(得分:2)
首先,您的实现非常接近State Pattern的经典示例。我看到的唯一问题是BlockInfo的作用。
如果在步骤之间更改BlockInfo,那么您的实现就是您需要做的。看看我引用的维基百科文章。在Mousedown,MouseMove和MouseUp之间更改了点,因此它必须是抽象工具的参数。
如果在步骤之间没有更改BlockInfo,那么您需要考虑几件事情。
如果实现ParsedDataHandler的类正在初始化BlockInfo结构的任何部分,那么我将其分离并使其成为该类的私有成员,并且只允许BlockInfo传递解析过程外部的初始化数据。
如果BeginBlock正在修改BlockInfo并将其传递给后续例程,那么您应该克隆BlockInfo,将其内部存储在实现ParsedDataHandler的类中。然后从参数列表中删除它。
如果之后需要BlockInfo,我会创建一个返回内部BlockInfo的readonly属性。
根据您的问题,我猜您应该将BlockInfo传递给BeginBlock并在内部存储它。从其他方法的参数中消除它,然后添加readonly属性,如果您需要检索它。