my Mediator pattern

Dec 15, 2009 at 1:42 AM
Edited Dec 15, 2009 at 1:44 AM

Hello! You can find PluginMediatorSample sample in my project, to see how I solve some caveeats just like in your blog ;)

http://plugins.codeplex.com/

    public class PluginMediator<T>
    {
        private readonly PluginDelegateMediator _delegateMediator = new PluginDelegateMediator();

        public void Register<U>(T target, string action, U delegateMethod)
        {
            if (delegateMethod is Delegate)
            {
                _delegateMediator.Add(target, action, delegateMethod);
            }
        }

        public void Unregister<U>(T target, string action, U delegateMethod)
        {
            if (delegateMethod is Delegate)
            {
                _delegateMediator.Remove(target, action, delegateMethod);
            }
        }

        public void Invoke<U>(string action, Action<U> actionMethod)
        {
            _delegateMediator.InvokeAction(action, actionMethod);
        }
    }

    public sealed class PluginDelegateMediator
    {
        readonly Dictionary<string, List<PluginWeakReferense>> _actionMap = new Dictionary<string, List<PluginWeakReferense>>();

        public void Add<T>(object target, string key, T item)
        {
            lock (_actionMap)
            {
                if (!_actionMap.ContainsKey(key))
                {
                    _actionMap[key] = new List<PluginWeakReferense>();
                }
                Delegate action = item as Delegate;
                if (action == null)
                {
                    throw new ArgumentException("Cannot process non-delegate target.");
                }
                List<PluginWeakReferense> weakActions = _actionMap[key];
                for (int i = weakActions.Count - 1; i > -1; --i)
                {
                    PluginWeakReferense weakAction = weakActions[i];
                    if (weakAction.Contains(target, action.Method, typeof(T)))
                    {
                        throw new ArgumentException("Cannot register method.");
                    }
                }
                _actionMap[key].Add(new PluginWeakReferense<T>(target, action.Method));
            }
        }

        public void Remove<T>(object target, string key, T item)
        {
            lock (_actionMap)
            {
                if (!_actionMap.ContainsKey(key))
                {
                    return;
                }
                Delegate action = item as Delegate;
                if (action == null)
                {
                    throw new ArgumentException("Cannot process non-delegate target.");
                }
                List<PluginWeakReferense> weakActions = _actionMap[key];
                for (int i = weakActions.Count - 1; i > -1; --i)
                {
                    PluginWeakReferense weakAction = weakActions[i];
                    if (weakAction.Contains(target, action.Method, typeof(T)))
                    {
                        weakActions.RemoveAt(i);
                    }
                }
                if (weakActions.Count == 0)
                    _actionMap.Remove(key);
            }
        }

        public void InvokeAction<T>(string action, Action<T> actionInvoker)
        {
            lock (_actionMap)
            {
                if (_actionMap.ContainsKey(action))
                {
                    List<PluginWeakReferense> weakReferences = _actionMap[action];
                    foreach (PluginWeakReferense weakReference in weakReferences)
                    {
                        if (weakReference.IsGenericType(typeof(T)))
                        {
                            ((PluginWeakReferense<T>)weakReference).DynamicInvoke(actionInvoker);
                        }
                    }
                }
            }
        }
    }

    public abstract class PluginWeakReferense
    {
        private readonly WeakReference _obj;
        private readonly MethodInfo _method;
        private readonly Type _type;

        protected PluginWeakReferense(WeakReference obj, MethodInfo method, Type type)
        {
            this._obj = obj;
            this._method = method;
            this._type = type;
        }

        protected void DynamicInvoke(Delegate actionInvoker)
        {
            if (_method.IsStatic)
            {
                actionInvoker.DynamicInvoke(Delegate.CreateDelegate(_type, _method));
            }
            else
            {
                actionInvoker.DynamicInvoke(Delegate.CreateDelegate(_type, _obj.Target, _method));
            }
        }

        public bool Contains(object target, MethodInfo method, Type type)
        {
            return _type == type && _method == method && (!_obj.IsAlive || _obj.Target == target);
        }

        public bool IsGenericType(Type type)
        {
            return _type == type;
        }
    }

    public sealed class PluginWeakReferense<T> : PluginWeakReferense
    {
        public PluginWeakReferense(object obj, MethodInfo method)
            : base(new WeakReference(obj), method, typeof(T))
        {
        }

        public void DynamicInvoke(Action<T> actionInvoker)
        {
            base.DynamicInvoke(actionInvoker);
        }
    }

    and usage is like that:

    public delegate void Test1Delegate(SomeData1 data);
    public delegate void Test2Delegate(SomeData2 data);

    public class BaseViewModel
    {
        static readonly PluginMediator<BaseViewModel> _mediator = new PluginMediator<BaseViewModel>();

        public PluginMediator<BaseViewModel> Mediator
        {
            get { return _mediator; }
        }
    }

    class A : BaseViewModel
    {
        public A()
        {
            Mediator.Register<Test1Delegate>(this, "message", Test1);
            MessageBox.Show(string.Format("+ {0}", typeof(A).Name));
        }

        private void Test1(SomeData1 data)
        {
            MessageBox.Show(string.Format("{0} : {1}", typeof(A).Name, data.Text));
        }

        ~A()
        {
            Mediator.Unregister<Test1Delegate>(this, "message", Test1);
            MessageBox.Show(string.Format("- {0}", typeof(A).Name));
        }
    }

    class B : A
    {
        public B()
        {
            Mediator.Register<Test2Delegate>(this, "message", Test2);
            MessageBox.Show(string.Format("+ {0}", typeof(B).Name));
        }

        private static void Test2(SomeData2 data)
        {
            MessageBox.Show(string.Format("{0} : {1}", typeof(B).Name, data.Value));
        }

        ~B()
        {
            Mediator.Unregister<Test2Delegate>(this, "message", Test2);
            MessageBox.Show(string.Format("- {0}", typeof(B).Name));
        }
    }

    class C : BaseViewModel
    {
        public C()
        {
            Mediator.Register<Test2Delegate>(this, "message", Test);
            MessageBox.Show(string.Format("+ {0}", typeof(C).Name));
        }
       
        private void Test(SomeData2 data)
        {
            MessageBox.Show(string.Format("{0} : {1}", typeof(C).Name, data.Value));
        }

        ~C()
        {
            Mediator.Unregister<Test2Delegate>(this, "message", Test);
            MessageBox.Show(string.Format("- {0}", typeof(C).Name));
        }
    }

    public class D : BaseViewModel
    {
        public void SendMessage1(string message)
        {
            SomeData1 data = new SomeData1 { Text = message };
            Mediator.Invoke<Test1Delegate>("message", (action) => action(data));
        }

        public void SendMessage2(int value)
        {
            SomeData2 data = new SomeData2 { Value = value };
            Mediator.Invoke<Test2Delegate>("message", (action) => action(data));
        }
    }

    public partial class Form1 : Form
    {
        private B b;
        private C c;
        private D d;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            d.SendMessage1("D");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            d.SendMessage2(4);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            c = null;
            GC.Collect();
        }

        private void button4_Click(object sender, EventArgs e)
        {
            b = null;
            GC.Collect();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            b = new B();
            c = new C();
            d = new D();
        }
    }