3

对于我们目前正在构建的发票系统,我很难理解基于状态的功能。该系统将支持发票的计算、人工审批、打印和存档。

起初我认为我们应该使用状态模式来对此进行建模。发票将是上下文,它将打印、归档等委托给其当前分配的状态。

但这显然是个坏主意,因为不同的状态(创建、批准、打印、存档)不应该支持相同的操作。例如,您不应该能够打印以前未经批准的发票。为不受支持的操作抛出异常将违反 LSP。我在这里找到了这个问题的一般描述。

有没有人有想法,如何适当地实施这个?


PS:我知道这听起来像是一些蹩脚的家庭作业,但事实并非如此;我需要这个用于现实世界的系统。

4

3 回答 3

1

您基本上是在创建应用程序状态的工作流,在每个状态下,发票上的可用操作都会发生变化。状态模式似乎不合适,但是如果您还创建了一些boolean canPrint()必须在调用之前使用的操作,您仍然可以使用它print()print()将有一个允许在canPrint()返回时抛出异常的合同false。这样,子类就不会破坏该契约。另一种选择是有一个boolean tryPrint(),它只会在可以打印的情况下打印,并返回是否打印。

但是,如果状态主要支持非重叠操作,那么状态模式可能不是解决方案。退后一步,寻找更好的方法,而不是试图让特定的模式适应你的问题。一种方法是为每个“状态”创建一个具有必要操作的单独类:like CreatedInvoiceApprovedInvoice等。这些类只有它们支持的操作。

于 2012-06-30T13:46:03.793 回答
0

责任链模式可能会对您有所帮助。

添加方式部分并修复链接。

可以有 Calculator、Approver、Printer 和 Archiver 类,它们是处理程序类。这些可以从父抽象类覆盖 processRequest()。Invoice 可以是传递给每个处理程序的 processRequest() 方法的类。在这里使用该模式的优点是可以动态添加较新的处理程序,并且可以轻松更改具有处理程序序列的链链接。

于 2012-06-30T13:37:31.067 回答
0

状态模式是否真的适合你的情况并不确定,但如果不是,Liskov 不是原因。抛出某种“当前状态下的无效操作”异常可以在状态接口中定义为可能且有效,然后这样做的子类不会违反 LSP。

GoF 设计模式一书中用于状态模式的经典示例是 TCPConnection,它肯定具有在所有状态下都不支持或不明智的操作。例如,您不能在关闭的连接上传输。

于 2012-06-30T14:21:03.960 回答