Pergunta

Eu tenho implementado minha própria cópia do padrão apresentador vista do modelo (na veia de cliente web fábrica de software) para que eu possa aproveitar meu próprio quadro DI em vez de ser amarrado a ObjectBuilder de WCSF que eu tinha inúmeros problemas com. Eu vim acima com algumas maneiras de fazê-lo, mas nenhum deles particularmente me fazer feliz. Eu queria saber se alguém tinha algumas outras ideias.

Solução # 1-A

Usa um HttpModule para interceptar context.PreRequestHandlerExecute chamar ObjectFactory.BuildUp (HttpContext.Current.Handler)

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

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

Solução # 1b

acúmulo de chamadas no carregamento da página, em vez de usar um 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);
    }
}

Solução # 1c

Acesso apresentador através Propriedade permitir Getter ao acúmulo se necessário.

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

Solução # 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;
        }
    }
}

Solução # 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;
        }
    }
}

Editar : Adicionado solução 1c, 2b

Foi útil?

Solução

Eu usaria solução # 1b, e criar um camada supertipo para todas as páginas, a fim de secar o apresentador de inicialização um pouco mais. assim:

código Página:

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 
    }

}

código Resumo Page:

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){}
}

Com esta solução você tem a inicialização apresentador (criado pelo ObjectFactory) em apenas uma classe, se necessário modificá-lo mais tarde você pode fazê-lo facilmente.

Editar:

deve Do_Load ser abstract ou virtual ?

Template Method originalmente afirma que o método deve ser abstrato, a fim de subclasses de força para implementar -lo, aderindo ao contrato superclasse. (Veja wikipedia exemplo de "Monopoly" < "Jogo").

Por outro lado, neste caso particular, nós não queremos forçar a classe de usuário para redefinir o nosso método, mas dar-lhe a chance de fazê-lo. Se você declará-lo abstrato, muitas classes serão obrigados a redefinir o método apenas para deixá-lo vazio (isto é claramente um cheiro de código). Então, nós fornecemos um padrão razoável (não fazer nada) e fazer o método virtual.

Outras dicas

Eu construí meu próprio framework MVP assim também. Eu encontrei a melhor maneira para mim foi usar os genéricos com uma classe de página base. Especificando o tipo Presenter na definição da classe genérica, eu começo a perder a maior parte do código que cada uma das suas propostas requer.

No entanto, há algumas coisas que eu não gosto em fazê-lo dessa forma. A definição de classe pode acabar parecendo um pouco complicado, e não é fácil de ler para um novato. Eu também não completamente funcionou uma boa maneira de usar o modelo de evento na página de base.

Desculpe eu não tenho o código para você aqui, mas eu posso postar algumas para você se desejar. Eu também tenho uma versão antiga do código afixado em www.codeplex.com/aspnetmvp, se você quiser ver como ele funciona.

Eu estive usando uma classe de página base com:

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

Os trabalhos de aproximação classe base em controles de usuário, assim, que só me impediu do módulo (não quero ter 2 maneiras de configurá-lo). Para que a página é

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

Eu injetar a vista através do construtor. Para evitar o problema de referência circular na configuração StructureMap, basta usar este método auxiliar:

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

Na utilização StructureMap configuração uma convenção para o apresentador e a vista de injecção.

Obrigado a todos pelo seu contributo muito valioso. Suas respostas cada me deu ideias valiosas para combinar juntos na minha solução final e isso é o que eu vim com:

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

E herdada por minha página original:

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
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top