سؤال

باستخدام MVP، ما هو الترتيب الطبيعي للبناء وحقن التبعية.

عادةً ما تقوم بإنشاء مقدم لكل عرض وتمرير العرض إلى مقدم العرض على المُنشئ.ولكن ماذا لو كان لديك:

  1. خدمة تحتاج وجهات نظر متعددة للاستماع إلى الأحداث فيها.
  2. تشير جميع طرق العرض المتعددة إلى نفس ذاكرة التخزين المؤقت لنموذج البيانات.

هل يمكن لشخص ما عرض التدفق الطبيعي للمعلومات من نقرة المستخدم إلى البيانات التي تعود في الخدمة من الخادم.

هل كانت مفيدة؟

المحلول

وهنا ما أفعله:

أولاً، أقوم بتحديد واجهات الأطروحات:

public interface IView<TPresenter>
{
    TPresenter Presenter { get; set; }
}

public interface IPresenter<TView, TPresenter>
    where TView : IView<TPresenter>
    where TPresenter : IPresenter<TView, TPresenter>
{
    TView View { get; set; }
}

ثم فئة مقدم العرض المجردة هذه:

public abstract class AbstractPresenter<TView, TPresenter> : IPresenter<TView, TPresenter>
    where TView : IView<TPresenter>
    where TPresenter : class, IPresenter<TView, TPresenter>
{
    protected TView view;

    public TView View
    {
        get { return this.view; }
        set
        {
            this.view = value;
            this.view.Presenter = this as TPresenter;
        }
    }
}

يتم إدخال العرض عبر خاصية، بدلاً من المُنشئ، للسماح بالتأثير ثنائي الاتجاه في أداة الضبط.لاحظ أن هناك حاجة إلى قالب آمن ...

إذن، مقدم العرض المحدد الخاص بي هو شيء من هذا القبيل:

public class MyPresenter : AbstractPresenter<IMyView, MyPresenter>
{
    //...
}

أين IMyView ينفذ IView.يجب أن يكون هناك نوع عرض ملموس (على سبيل المثال. MyView)، ولكن الحاوية هي التي تحل المشكلة:

  1. انا اسجل MyPresenter اكتب كما هو في الحاوية، مع سلوك عابر.
  2. انا اسجل MyView ك IMyView في الحاوية مع سلوك عابر.
  3. ثم أطلب أ MyPresenter إلى الحاوية.
  4. تقوم الحاوية بإنشاء مثيل MyView
  5. إنه يجسد أ MyPresenter
  6. يقوم بحقن العرض في مقدم العرض من خلال AbstractPresenter.View ملكية.
  7. يكمل رمز الضبط الارتباط ثنائي الاتجاه
  8. تُرجع الحاوية الزوجين المقدم/العرض

فهو يسمح لك بإدخال تبعيات أخرى (الخدمات، اتفاقيات إعادة الشراء) في كل من العرض الخاص بك ومقدم العرض الخاص بك. ولكن في السيناريو الذي وصفته، أنصحك بإدخال الخدمات وذاكرة التخزين المؤقت في ملف مقدم, ، بدلاً من العرض.

نصائح أخرى

في WinForms، أفضل النهج البسيط.عادةً ما تتعامل مع عدد قليل من عناصر تحكم المستخدم على سطح التصميم - اجعل هذه فئات العرض الخاصة بك.يقوم .NET بإنشاء التسلسل الهرمي للتحكم لك (عبر التهيئة Component).إذا كنت تستخدم عرض سلبي النمط، ثم يقوم كل عرض بإنشاء مثيل لمقدمه.(يمكنك القيام بذلك إما مباشرة أو عن طريق طلب حاوية IOC.) استخدم حقن المنشئ لتمرير مرجع إلى واجهة العرض إلى مُنشئ مقدم العرض.يمكن للمقدم بعد ذلك توصيل نفسه لعرض الأحداث.كرر العملية للنموذج:يقوم المقدم بإنشاء نموذج وربطه بأحداثه.(في هذه الحالة، لا تحتاج إلى حقن المنشئ نظرًا لأن العرض السلبي يقول أن مقدم العرض يحتفظ بمرجع إلى النموذج، وليس العكس.)

المشكلة الوحيدة التي وجدتها في هذا النهج هي إدارة عمر النموذج والمقدم بشكل صحيح.أنت تريد إبقاء العرض بسيطًا قدر الإمكان، لذلك ربما لا ترغب في الاحتفاظ بمرجع للمقدم.ومع ذلك، هذا يعني أن لديك كائن مقدم العرض هذا معلقًا مع ربط معالجات الأحداث بطريقة العرض الخاصة بك.يمنع هذا الإعداد طريقة العرض الخاصة بك من تجميع البيانات المهملة.أحد الحلول هو جعل طريقة العرض الخاصة بك تنشر حدثًا يشير إلى إغلاقه.سيتلقى مقدم العرض الحدث ويزيل كلاً من نموذجه ويعرض الاشتراكات.تمت الآن إلغاء الإشارة إلى الكائنات الموجودة في الويب لديك بشكل صحيح ويمكن لمجمع البيانات المهملة القيام بعمله.

ينتهي بك الأمر بشيء مثل ما يلي:

public interface IView
{
   ...
   event Action SomeEvent;
   event EventHandler Disposed;
   ...
}

// Note that the IView.Disposed event is implemented by the 
// UserControl.Disposed event. 
public class View : UserControl, IView
{
   public event Action SomeEvent;

   public View()
   {
      var presenter = new Presenter(this);
   }
}

public interface IModel
{
   ...
   event Action ModelChanged;
   ...
}

public class Model : IModel
{
   ...
   public event Action ModelChanged;
   ...
}

public class Presenter
{
   private IView MyView;
   private IModel MyModel;

   public Presenter(View view)
   {
      MyView = view;
      MyView.SomeEvent += RespondToSomeEvent;
      MyView.Disposed += ViewDisposed;

      MyModel = new Model();
      MyModel.ModelChanged += RespondToModelChanged;
   }

   // You could take this a step further by implementing IDisposable on the
   // presenter and having View.Dispose() trigger Presenter.Dispose().
   private void ViewDisposed(object sender, EventArgs e)
   {
      MyView.SomeEvent -= RespondToSomeEvent;
      MyView.Disposed -= ViewDisposed;
      MyView = null;

      MyModel.Modelchanged -= RespondToModelChanged;
      MyModel = null;
   }
}

يمكنك فصل هذا المثال خطوة أخرى باستخدام IOC ومطالبة حاوية IOC الخاصة بك بتنفيذ IModel (في فئة Presenter) وIPresenter (في فئة View).

interface IEmployee
{
    int EmployeeId {get;}
    string FirstName {get;}
    string LastName {get;}
}
interface IEmployeeRepository
{
    void SaveEmployee(IEmployee employee);
    IEmployee GetEmployeeById(int employeeId);
    IEmployee[] Employees { get; }
}
interface IEmployeeView
{
    event Action<IEmployee> OnEmployeeSaved;
}

interface IEmployeeController
{
    IEmployeeView View {get;}
    IEmployeeRepository Repository {get;}
    IEmployee[] Employees {get;}        
}

partial class EmployeeView: UserControl, IEmployeeView
{
    public EmployeeView()
    {
        InitComponent();
    }
}
class EmployeeController:IEmployeeController
{
    private IEmployeeView view;
    private IEmployeeRepository repository;
    public EmployeeController(IEmployeeView view, IEmployeeRepository repository)
    {
        this.repository = repository;
        this.view = view;
        this.view.OnEmployeeSaved+=new Action<IEmployee>(view_OnEmployeeSaved);
    }

    void  view_OnEmployeeSaved(IEmployee employee)
    {
        repository.SaveEmployee(employee);
    }
    public IEmployeeView View 
    {
        get
        { 
            return view;
        }
    }
    public IEmployeeRepository Repository
    {
        get
        {
            return repository;
        }
    }

    public IEmployee[] Employees
    {
        get 
        {
            return repository.Employees;
        }
    }
}

يعد WinformsMVP إطار عمل MVP جيدًا جدًا لنماذج Windows.يمكنك بسهولة إدخال خدمة عبر طرق عرض متعددة بسهولة باستخدام هذا الإطار. هذا مقالة جيدة تتضمن نموذجًا للكود المصدري يشرح كيفية استخدام إطار العمل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top