【问题标题】:Presenter injection in Model-View-Presenter pattern with StructureMap使用 StructureMap 的模型-视图-演示者模式中的演示者注入
【发布时间】:2010-10-05 14:31:02
【问题描述】:

我已经实现了我自己的模型视图演示者模式副本(在 Web 客户端软件工厂的脉络中),因此我可以利用我自己的 DI 框架,而不是依赖于我遇到很多问题的 WCSF 的 ObjectBuilder。我想出了一些方法来做到这一点,但没有一个让我特别高兴。我想知道其他人是否有其他想法。

解决方案 #1a

使用 HttpModule 拦截 context.PreRequestHandlerExecute 调用 ObjectFactory.BuildUp(HttpContext.Current.Handler)

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

解决方案 #1b

在页面加载时调用 buildup 而不是使用 HttpModule

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        ObjectFactory.BuildUp(this);
    }
}

解决方案 #1c

如果需要,通过 Property 访问 Presenter 允许 Getter 进行 BuildUp。

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    public EmployeePresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                ObjectFactory.BuildUp(this);
            }

            return _presenter;
        }
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

解决方案 #2

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                _presenter = ObjectFactory.GetInstance<EmployeePresenter>();
                _presenter.View = this;
            }

            return _presenter;
        }
    }
}

解决方案 #2b

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                Presenter = ObjectFactory.GetInstance<EmployeePresenter>();
            }

            return _presenter;
        }
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

编辑:添加解决方案 1c、2b

【问题讨论】:

    标签: c# dependency-injection structuremap mvp


    【解决方案1】:

    我会使用解决方案 #1b,并为所有页面创建一个layer supertype,以便进一步干燥演示者初始化。像这样:

    页面代码:

    public partial class _Default : AbstractPage, IEmployeeView
    {
        private EmployeePresenter presenter;
    
        private EmployeePresenter Presenter
        {
            set
            {
                presenter = value;
                presenter.View = this;
            }
        }
        protected override void Do_Load(object sender, EventArgs args)
        {
            //do "on load" stuff 
        }
    
    }
    

    摘要页面代码:

    public abstract class AbstractPage : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            ObjectFactory.BuildUp(this);
            this.Do_Load(sender,e); 
            //template method, to enable subclasses to mimic "Page_load" event
    
        }
        //Default Implementation (do nothing)
        protected virtual void Do_Load(object sender, EventArgs e){}
    }
    

    使用此解决方案,您只需在一个类中进行演示者初始化(由 ObjectFactory 创建),如果您以后需要修改它,您可以轻松完成。

    编辑:

    Do_Load 应该是抽象的还是虚拟的

    Template Method 最初声明该方法应该是抽象的,以便强制子类实现它,遵守超类契约。 (参见“垄断”

    另一方面,在这种特殊情况下,我们不想强制用户类重新定义我们的方法,而是给它这样做的机会。如果您将其声明为抽象的,许多类将不得不重新定义该方法以使其为空(这显然是代码异味)。所以我们提供了一个合理的默认值(什么都不做)并使方法虚拟化。

    【讨论】:

    • 这可能是公认的答案,我唯一在决定 Do_Load 是更好地标记为虚拟还是抽象时遇到的问题。
    【解决方案2】:

    我也建立了自己的 MVP 框架。我发现对我来说最好的方法是将泛型与基页类一起使用。通过在泛型类定义中指定 Presenter 类型,我会错过您的每个提案所需的大部分代码。

    但是,我不喜欢这样做。类定义最终可能看起来相当复杂,并且对于新手来说不容易阅读。我还没有完全想出在基本页面中使用事件模型的好方法。

    抱歉,这里没有适合您的代码,但如果您愿意,我可以为您发布一些代码。我还在 www.codeplex.com/aspnetmvp 上发布了旧版本的代码,如果您想看看它是如何工作的。

    【讨论】:

      【解决方案3】:

      我一直在使用一个基页面类:

      protected override void OnInit(EventArgs e)
          {
              StructureMap.ObjectFactory.BuildUp(this);
              base.OnInit(e);
          }
      

      基类方法也适用于用户控件,仅此一项就让我远离了模块(不想有两种方法来设置它)。 对于页面是

      public partial class Employee : View, IEmployeeView
      {
          public ViewPresenter Presenter { get; set; }
          private void Page_Load(object sender, EventArgs e){}
      }
      

      我通过构造函数注入视图。为避免结构映射配置上的循环引用问题,只需使用此辅助方法:

      static T GetView<T>()
      {
          return (T) HttpContext.Current.Handler;
      }
      

      在结构映射配置中,为演示者和视图注入使用约定。

      【讨论】:

        【解决方案4】:

        感谢大家的宝贵意见。您的每一个回答都为我提供了宝贵的想法,可以将它们组合在一起形成最终的解决方案,这就是我想出的:

        public abstract class ViewBasePage<TPresenter, TView> :
            Page where TPresenter : Presenter<TView>
        {
            protected TPresenter _presenter;
        
            public TPresenter Presenter
            {
                set
                {
                    _presenter = value;
                    _presenter.View = GetView();
                }
            }
        
            /// <summary>
            /// Gets the view. This will get the page during the ASP.NET
            /// life cycle where the physical page inherits the view
            /// </summary>
            /// <returns></returns>    
            private static TView GetView()
            {
                return (TView) HttpContext.Current.Handler;
            }
        
            protected override void OnPreInit(EventArgs e)
            {
                ObjectFactory.BuildUp(this);
                base.OnPreInit(e);
            }
        }
        

        并由我的原始页面继承:

        public partial class _Default : 
            ViewBasePage<EmployeePresenter, IEmployeeView>, IEmployeeView
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!Page.IsPostBack)
                {
                    _presenter.OnViewInitialized();
                }
        
                _presenter.OnViewLoaded();
                Page.DataBind();
            }
        
            #region Implementation of IEmployeeView
        
            ...
        
            #endregion
        }
        

        【讨论】:

          猜你喜欢
          • 2015-07-23
          • 2011-06-15
          • 2014-10-31
          • 2020-01-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多