代码之家  ›  专栏  ›  技术社区  ›  Michael Klement

在我的设计中实现定制挂钩的最佳方法

  •  3
  • Michael Klement  · 技术社区  · 15 年前

    我想知道在我的应用程序中插入定制挂钩的最佳方式是什么。基本上,我的应用程序分为两个程序集:一个 Core 包含所有业务逻辑和 UserInterface

    我考虑过使用事件来实现这一点。通过在我的核心类中添加一些事件,我的控制器类将能够为某些客户订阅或取消订阅实现这些偏差的方法。

    我可以想出两种方法:手动添加这些绑定,或者如果存在异常方法,则让它们自动添加。我在为后者考虑这样的事情:

    foreach (Order order in form.SelectedOrders) {
        CustomerExtension customer = customerExtensions[order.Customer];
    
        if(Exists(customer.StatusChanging(...)) // Pseudo Code!
                OrderManager.StatusChanging += new StatusChangingEventHandler(customer.StatusChanging(...));
    
        order.SetStatus(newStatus);
    
        if(Exists(customer.StatusChanging(...)) // Pseudo Code!
                OrderManager.StatusChanging -= new StatusChangingEventHandler(customer.StatusChanging(...));
    }
    

    我想我必须使用反射来实现这一点,但这对于需要多次执行的操作是否可行?

    或者有没有更好的方法来添加定制挂钩,同时让我在客户基础上集中偏差?

    [编辑]完全修改了问题。

    3 回复  |  直到 15 年前
        1
  •  3
  •   Fabrizio C.    15 年前

    我认为你甚至可以不举办活动(它们是你想要的结构吗?)。我试着整理一些东西:试着看一下代码(不要太在意细节),如果你想让我详细说明的话,请告诉我…:-)

    // Begin personalization assembly (one of many)-----------------------
    
    /// <summary>
    /// Here you could use an attribute to allow clean reflection
    /// </summary>
    // [CustomerSpecific("Acme")]
    public class AcmeCustomization : BaseCustomization
    {
        public override void OnStatusChanged()
        {
            base.OnStatusChanged();
            // do what you need to customize
        }
    }
    // End personalization assembly (one of them)-------------------------
    
    // Begin core assembly -----------------------------------------------
    public interface ICustomization
    {
        void OnStatusChanged();
    }
    
    /// <summary>
    /// This class is optional of course, but can be useful
    /// </summary>
    public class BaseCustomization : ICustomization
    {
        public virtual void OnStatusChanged()
        {
            // intentionally empty
        }
    }
    
    class CustomizationFactory
    {
        public ICustomization GetCustomization(string order)
        {
            // Here you could
            // - hardcode (as you did in your solution)
            // - use reflection (various ways)
            // - use an external mapping file
            // - use MEF (!)
            // and then
            // - do instance caching
            // - whatever...
    
            // I'm lazy ;-)
            return null;
        }
    }
    
    class OrderManager
    {
        private ICustomization _customization = null;
    
        public void SetStatus(string order, int status)
        {
            // Do some work
            this.OnStatusChanged();
            // Do some other work
        }
    
        protected void OnStatusChanged()
        {
            if (_customization != null)
            {
                _customization.OnStatusChanged();
            }
        }
    
        public void SetCustomization(ICustomization customization)
        {
            _customization = customization;
        }
    
        public void ClearCustomization()
        {
            _customization = null;
        }
    }
    // End core assembly -------------------------------------------------
    
    class Program
    {
        static void Main(string[] args)
        {
            CustomizationFactory factory = new CustomizationFactory();
            OrderManager manager = new OrderManager();
    
            // here I'm just pretending to have "orders"
            var orders = new string[] { 
                "abc",
                "def"
            };
    
            const int newStatus = 42;
    
            foreach (var order in orders)
            {
                manager.SetCustomization(factory.GetCustomization(order));
                manager.SetStatus(order, newStatus);
                manager.ClearCustomization();
            }
        }
    }
    

        2
  •  1
  •   Taylor Leese    15 年前

    abstract class SomeBaseClass
    {
    
       public void DoSomething()
       {
           ...
           somethingElse();
           ...
       }
    
       abstract void somethingElse();
    
    }
    
    public class CompanyA : SomeBaseClass
    {
        void somethingElse()
        {
           // do something specific
        }
    }
    
    public class CompanyB : SomeBaseClass
    {
        void somethingElse()
        {
           // do something specific
        }
    }
    
        3
  •  0
  •   Michael Klement    15 年前

    因此,我已经实现了我关于使用事件的想法,到目前为止,我对它非常满意。

    唯一的缺点是,我必须手动添加/删除控制器类中的订阅处理。例如,我的 SetStatus

    foreach (Job job in form.SelectedJobs) {
        // Subscribe customer-specific methods to events
        switch (job.Customer.Code) {
                case "VNR":
                        jobManager.JobStatusChanged += new JobManager
                            .JobStatusChangedHandler(Vnr.OnStatusChanged);
                        break;
                case "LS":
                        jobManager.JobStatusChanged += new JobManager
                            .JobStatusChangedHandler(Ls.OnStatusChanged);
                        break;
        }
    
        jobManager.SetStatus(job, status);
    
        // Unsubscribe customer-specific methods from events
        switch (job.Customer.Code) {
                case "VNR":
                        jobManager.JobStatusChanged -= new JobManager
                            .JobStatusChangedHandler(Vnr.OnStatusChanged);
                        break;
                case "LS":
                        jobManager.JobStatusChanged -= new JobManager
                            .JobStatusChangedHandler(Ls.OnStatusChanged);
                        break;
        }
    }
    

    这真的不是很优雅,但也没那么糟糕。

    推荐文章