【问题标题】:Refactor to Design Pattern: displaying/hiding different combinations of controls based on state重构设计模式:根据状态显示/隐藏不同的控件组合
【发布时间】:2009-05-26 20:05:40
【问题描述】:

假设您的控件 A、B、C、D 和 E 都具有 Visibility 属性。您还有状态 1、2、3、4、5 和 6,其中将显示您的控件的各种组合。

目前这是由每个状态的 switch 语句处理的:即

Select Case PageState
    case "1"
      a.visible = false
      b.visible = true
      c.visible = false 
      d.visible = true
      e.visible = false
   case "2"
      a.visible = true
      b.visible = true
      c.visible = false 
      d.visible = true
      e.visible = false
  case ... 
 End Select

正如您可以想象的那样,这会变得很痛苦,因为每个状态都需要每个控件的显示/隐藏语句。我怎样才能重构它,以便添加控件和/或状态变得微不足道?

我的第一反应是扩展控件并添加应显示的状态集合,但这听起来有点矫枉过正。

编辑 我故意含糊其辞,以防这有其他含义。在我当前的实例中,有问题的“控件”是 ASP 面板。这有什么改变吗?

【问题讨论】:

    标签: asp.net vb.net design-patterns


    【解决方案1】:

    【讨论】:

      【解决方案2】:

      使用状态模式。让每个状态在您的页面上运行(抽象为一个界面):

      public interface IControlSituationPage // your page implements this
      {
          void SetAvisibility(bool visibility);
          void SetBVisibility(bool visibility);
          ...
      }
      

      ....

      public interface PageState // each state implements this
      {
          void ApplyState(IControlSituationPage page);
      }
      

      .. 然后,在确定您处于哪种状态(可能是工厂模式)之后,调用该方法:

      // ... somewhere..
      _state.ApplyState(this);
      

      当然,这代替了实际使用更健壮的表示模式,如 MVC 或 MVP。

      【讨论】:

      • 虽然我很想将其重做为 MVC,但这超出了我目前的工作范围。我将不得不接受重构。
      • 如果我错了,请纠正我,但在这种情况下,添加控件意味着更新接口,那么该接口的所有实现(每个状态)不是吗?
      • 和测试,是的。使用 resharper 或其他工具大约需要 1 分钟。
      【解决方案3】:

      [注意:我是一个 java 人,所以我下面的实现是用 Java 实现的——它应该与 C# 或您想使用的任何其他语言非常相似]

      Rob 指出了上述解决方案的问题——它确实不可维护。

      它也非常冗长(GoF 状态模式通常是......)。

      有时状态模式并不是你真正应该使用的。

      您要彻底解决问题,让数据驱动它吗?

      将其视为“应该为哪些状态显示 X?”

      尝试以下方法:

      1. 创建一个代表您的状态的枚举
      2. 为每个控件创建一个 EnumSet(它们非常高效)
      3. 在每个 EnumSet 中,添加该控件应该可见的状态
      4. 当状态改变时,检查每个控件的可见性

      一个粗略的实现(未编译/测试)

      public enum MyStates {State1, State2, State3...}
      
      public class VisibilityManager {
          private Map<Component, Set<MyStates>> managedComponents =
              new HashMap<Component, Set<MyStates>>();
          private Component component;
          public void setVisibility(Component component, MyStates... states) {
              Set<MyStates> visibleStates = EnumSet.of(states);
              managedComponents.put(component, states);
          }
          public void update(MyStates currentState) {
              for (Map.Entry<Component, Set<MyStates>> e : managedComponents.entrySet())
                  e.getKey().setVisible(e.getValue().contains(currentState));
          }
      }
      
      // then in your GUI setup
      
      VisibilityManager v = new VisibilityManager();
      v.setVisibility(comp1, MyStates.State1, MyStates.State2);
      v.setVisibility(comp1, MyStates.State3);
      v.setVisibility(comp1, MyStates.State1, MyStates.State3, MyStates.State5);
      ...
      
      // and when you change the state
      v.update(newState);
      

      希望这会有所帮助!

      【讨论】:

        【解决方案4】:

        Scott 明白了这一点 - 对于这种微不足道的情况(当您只需要控制可见性时),采用相反的逻辑是有意义的。如果您需要执行状态转换并使您的 UI 从业务逻辑中抽象出来,状态模式将变得非常有用。

        【讨论】:

          猜你喜欢
          • 2022-10-25
          • 1970-01-01
          • 2018-03-29
          • 1970-01-01
          • 2017-10-23
          • 2016-02-16
          • 1970-01-01
          • 2015-08-10
          • 2020-02-29
          相关资源
          最近更新 更多