6

我已经实现了我自己的模型视图演示者模式副本(在 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

4

4 回答 4

7

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

页面代码:

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 应该是抽象的还是虚拟的?

模板方法最初声明该方法应该是抽象的,以强制子类实现它,遵守超类契约。(参见“垄断”<“游戏”的维基百科示例)。

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

于 2009-02-10T05:38:41.873 回答
1

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

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;
}

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

于 2009-02-14T08:02:52.360 回答
1

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

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

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

于 2009-02-14T09:04:03.693 回答
0

谢谢大家非常宝贵的意见。您的每一个回答都给了我宝贵的想法,可以在我的最终解决方案中结合起来,这就是我想出的:

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
}
于 2009-02-15T21:41:38.050 回答