状态模式可以帮助只读状态吗?
我正在尝试对某个过程进行建模,并且我认为状态模式可能是一个很好的匹配。我希望得到您的反馈,了解 State 是否适合我的需求以及它应如何与我的持久性机制相结合。
我有一个 CMS,其中包含许多对象,例如页面。这些对象(我们将使用页面示例,但大多数对象都是如此)可以处于多种状态之一,3 个示例是: 未发表 已发表 返工
未发布时,它们是可编辑的。一旦发布,它们就不可编辑,但可以进入返工状态。在返工状态下,它们可以再次编辑并且可以重新发布。
显然,这些页面是否可编辑的决定应该由模型本身而不是 UI 决定。于是,State 模式就出现在我的脑海中。但是,如何防止为对象的属性赋值?检查每个属性设置器似乎是一个坏主意:
if (!CurrentState.ReadOnly)
有什么想法如何工作吗?有更好的模式吗?
I'm trying to model a certain process and I'm thinking that the State Pattern might be a good match. I'd like to get your feedback though about whether State will suit my needs and how it should be combined with my persistence mechanism.
I have a CMS that has numerous objects, for example, Pages. These objects (we'll use the example of Pages, but it's true of most objects) can be in one of a number of states, 3 examples are:
Unpublished
Published
Reworking
When Unpublished, they are editable. Once Published, they are not editable, but can be moved into the Reworking state. In the Reworking state they are editable again and can be Republished.
Obviously the decision for whether these Pages are editable should be in the models themselves and not the UI. So, the State pattern popped into mind. However, how can I prevent assigning values to the object's properties? It seems like a bad idea to have a check on each property setter:
if (!CurrentState.ReadOnly)
Any ideas how to work this? Is there a better pattern for this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用维基百科的 Java 示例,该结构有一个 Context,它调用在基础中定义的方法状态,具体状态会覆盖该状态。
在您的情况下,上下文是一些东西就像一页。在某些状态下,
edit()
方法只是一个无操作。上下文上的某些操作可能会隐式执行状态更改。客户端代码中永远不需要测试您所处的状态。Using wikipedia's Java example, the structure has a Context, which calls methods defined in the base State, which the concrete states override.
In your case, the context is something like a page. In some states, the
edit()
method is simply a no-op. Some of the actions on the context may execute a state change implicitly. There is never any need in the client code to test which state you are in.更新:
今天早上我实际上想到了一种方法,该方法可以适用于您的具体情况并且更容易维护。我将在这里保留原来的两点,但我将推荐最终选项,因此请跳到“更好的方法”部分。
创建一个
ThrowIfReadOnly
方法,该方法按照其说明执行操作。这稍微减少了重复性并避免了嵌套。使用接口。有一个实现所需功能的
IPage
,让每个公共方法返回一个IPage
,然后有两个实现,一个EditablePage
和一个只读页面
。每当有人尝试修改ReadOnlyPage
时,它就会抛出异常。还要在IPage
接口上放置一个IsReadOnly
属性(或State
属性),以便消费者可以实际检查状态,而不必捕获异常。< /p>选项 (2) 或多或少是
IList
和ReadOnlyCollection
协同工作的方式。它为您省去了在每个方法开始时进行检查的麻烦(从而消除了忘记验证的风险),但要求您维护两个类。--更好的方法--
正确的技术规范将有助于澄清这个问题。我们这里真正拥有的是:
真正需要抽象的并不是动作本身,而是所述动作的执行。因此,一点点功能性的优点将在这里帮助我们:
现在编写类本身几乎变得微不足道:
这不仅或多或少地实现了状态模式,而且您不需要维护单独的类,甚至不需要维护单独的类。不同状态的单独代码路径。例如,如果您想将
InvalidOperationException
转换为无操作,只需从Write
方法中删除throw
语句即可。或者,如果您想添加其他状态,例如Reviewing
或类似的状态,您只需添加一个case
行。这不会为您处理状态转换,也不会处理任何根据状态执行不同操作的真正复杂的操作(除了“成功”或“失败”之外),但听起来您并不需要这样做。因此,这为您提供了一个几乎不需要使用额外代码的嵌入式状态实现。
当然,仍然可以选择依赖注入/AOP,但显然这种方法会带来很多开销,而且我可能不会将它用于如此简单的事情。
Update:
I actually thought of a method this morning that would work with your specific case and be a lot easier to maintain. I'll leave the original two points here, but I'm going to recommend the final option instead, so skip to the "better method" section.
Create a
ThrowIfReadOnly
method, which does what it says on the tin. This is slightly less repetitive and avoids the nesting.Use an interface. Have an
IPage
that implements the functionality you want, have every public method return anIPage
, then have two implementations, anEditablePage
and aReadOnlyPage
. TheReadOnlyPage
just throws an exception whenever someone tries to modify it. Also put anIsReadOnly
property (orState
property) on theIPage
interface so consumers can actually check the status without having to catch an exception.Option (2) is more or less how
IList
andReadOnlyCollection<T>
work together. It saves you the trouble of having to do a check at the beginning of every method (thus eliminating the risk of forgetting to validate), but requires you to maintain two classes.-- Better Method --
A proper technical spec would help a lot to clarify this problem. What we really have here is:
What really needs to be abstracted is not so much the action itself, but the execution of said action. Therefore, a little bit of functional goodness will help us here:
Now it becomes almost trivial to write the classes themselves:
Not only does this more-or-less implement the State pattern, but you don't need to maintain separate classes or even separate code paths for the different states. If you want to, for example, turn the
InvalidOperationException
into a no-op, just remove thethrow
statement from theWrite
method. Or, if you want to add an additional state, likeReviewing
or something like that, you just need to add onecase
line.This won't handle state transitions for you or any really complex actions that do different things depending on the state (other than just "succeed" or "fail"), but it doesn't sound like you need that. So this gives you a drop-in state implementation that requires almost no extra code to use.
Of course, there's still the option of dependency injection/AOP, but there's obviously a lot of overhead associated with that approach, and I probably wouldn't use it for something so simple.