在MVP赢得表单应用程序的设计问题
本文关键字:问题 应用程序 表单 MVP | 更新日期: 2023-09-27 18:02:44
在win forms应用程序的模块中,我有一个像BaseRecovery
, LoanRecovery
和FineRecovery
这样的类的层次结构。LoanRecovery
和FineRecovery
都继承自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
创建一个依赖的子对象。谁能提出一个更好的设计来解决这个问题?
好的,如果我理解正确的话,你的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;
}