在MVP赢得表单应用程序的设计问题

本文关键字:问题 应用程序 表单 MVP | 更新日期: 2023-09-27 18:02:44

在win forms应用程序的模块中,我有一个像BaseRecovery, LoanRecoveryFineRecovery这样的类的层次结构。LoanRecoveryFineRecovery都继承自BaseRecovery。所有这些模型都有一个名为RecoveryForm的视图,您可以在其中输入/查看员工的贷款和罚款。我计划使用一个名为RecoveryPresenter的演示器类,它继承自BasePresenter。我们有一个DataService类用于db事务

LoanRecovery类是这样的…

Class LoanRecovery : BaseRecovery
{
    public string LoanID {get;set;}
    public DateTime IssueDate {get;set;}
    public Decimal Amount {get;set;}
    .
    .
    .
}

所以我在program .cs.

中做如下操作
IBaseRcovery recovery=null;
IRecoveryForm recoveryForm = new RecoveryForm();
IDataService dataService = new DataService();
BasePresenter presenter = new RecoveryPresenter( recovery, recoveryForm, dataService );
presenter.Show(); // This will display the form recoveryForm

在presenter中我会说

public RecoveryPresenter( IBaseRecover model, IRecoveryForm view, IDataService dataService )
{
    this._Model = model;
    this._View = view;
    this._DataService = dataService;            
    WireUpViewEvents();
}

现在让我们说,如果我需要提供贷款,我会在使用反射的BasePresenter类中运行SetModelPropertisFromView()方法。但在此之前,我应该通过LoanRecovery类(即_Model)的实例与_View一起该方法。同样,我们可以对所有的子类做同样的事情,如下所示…

    public void Issue()
    {
        if (_View.Type == "Loan")
        {
            _Model = new LoanRecovery();
            SetModelPropertiesFromView(_Model, _View, _DataService);
            _dataService.InsertLoan(_Model); //Error
        }
        if (_View.Type == "Fine")
        {
            _Model = new FineRecovery();
            SetModelPropertiesFromView(_Model, _View, _DataService);
            _DataService.InsertFine(_Model); //Error
        }
        if (_View.Type == "Insurance")
        {
            _Model = new InsuranceRecovery();
            SetModelPropertiesFromView(_Model, _View, _DataService);
            _DataService.InsertFine(_Model); //Error
        }

    } 

一切正常,直到上面if块的最后一行。问题是DataService类中的数据访问方法需要子实例而不是基类实例。

  public void InsertLoan( LoanRecovery loan)
    {
        using (SqlConnection sqlConnection = new SqlConnection(db.GetConnectionString))
        {
            SqlCommand sqlCommand = new SqlCommand("BEGIN INSERT INTO recovery ;
            sqlCommand.Parameters.Add("@empID", SqlDbType.Char).Value = loan.EmployeeID;
            sqlCommand.Parameters.Add("@loanType", SqlDbType.VarChar).Value = loan.Type;
            sqlCommand.Parameters.Add("@loanAmount", SqlDbType.Decimal).Value = loan.FullAmount;
            sqlCommand.Parameters.Add("@loanDuration", SqlDbType.Int).Value = loan.Duration;
            sqlConnection.Open();
            sqlCommand.ExecuteNonQuery();
        }
    }

所以我这样解决了这个问题…

    public void Issue()
    {
        if (_View.Type == "Loan")
        {
            LoanRecovery loanModel = new LoanRecovery(); //Creates a child instance
            SetModelPropertiesFromView(loanModel, _View, _DataService);
            _DataService.InsertLoan(loanModel);
        }
    }

现在它的工作,但我担心的是,在这里我不使用注入的实例,通过构造函数而不是newing创建一个依赖的子对象。谁能提出一个更好的设计来解决这个问题?

在MVP赢得表单应用程序的设计问题

好的,如果我理解正确的话,你的IDataService接口有特定的方法来保存实现IBaseRecover的具体类,但是要调用正确的保存方法,你需要知道IBaseRecover的具体类型。为什么不把保存职责推到ibaserrecover的具体实现中,因为它们最清楚应该调用哪个方法。你可以这样做:

interface IBaseRecover{
    void Save();
    ....
}

class LoanRecovery : IBaseRecover {
    private IDataService _dataService;
    LoadRecovery(IDataService dataService){
        _dataService = dataService;
    }}
    void Save(){
       _dataService.InsertLoan(this);
    }
}

好吧,根据你的评论,我有另一个想法。我认为这里的复杂性来自于这样一个事实,你正在使用一个视图,它可以表示三种不同类型的模型,即使它们都派生自相同的基类,你的视图有特定于每个实现的输入。这很好,但我认为你会从MVP模式的另一种变化中受益。Martin Fowler将MVP模式分解为监督控制器和被动视图。我认为被动视角在这里对你很有用。在这种情况下,你的视图会将它的输入元素的值作为属性公开,这样呈现者就可以获得恢复属性,比如IssueDate和Amount,而不必知道视图组件。因此,视图上Insert Action的代码可能如下所示:

public decimal Amount{
    get{
        return Convert.ToDecimal(txtAmount.text);
    }
}
void btnInsert_Click(Object sender, EventArgs e){
    presenter.Insert();
}

注意你的视图可以有一个Presenter的实例。现在演示者插入方法可能看起来像这样:

public void Insert(){
    if(_view.Type == "Loan"){
       var model = new LoadRecovery();
       model.IssueDate = _view.IssueDate;
       model.Amount = _view.Amount;
       _dataService.InsertLoan(model);
    }
}

如果你第一次显示的是要更新的恢复,而不是插入:

public void Show(){
    _view.IssueDate = model.IssueDate;
    _view.Amount = model.Amount;
}