代码之家  ›  专栏  ›  技术社区  ›  jason

讨厌的黑客行为(基类上使用反射的工厂方法)

  •  3
  • jason  · 技术社区  · 15 年前

    这是一件肮脏的事,我觉得这样做很肮脏:

    public abstract class InterestRate {
    
        // irrelevant details
    
        public static T ImpliedRate<T>(
            double factor,
            double time,
            DayCounter dayCounter
        ) where T : NonCompoundedInterestRate {
            MethodInfo methodInfo = typeof(T).GetMethod(
                "ImpliedRate",
                BindingFlags.Static);
            return (T)methodInfo.Invoke(
                null,
                new object[] { factor, time, dayCounter }
            );
        }
    
        public static T ImpliedRate<T>(
            double factor,
            double time,
            DayCounter dayCounter,
            Frequency frequency
        ) where T : CompoundedInterestRate {
            MethodInfo methodInfo = typeof(T).GetMethod(
                "ImpliedRate",
                BindingFlags.Static);
            return (T)methodInfo.Invoke(
                null,
                new object[] { factor, time, dayCounter, frequency }
            );
    }
    

    NonCompoundedInterestRate (摘要)和 CompoundedInterestRate InterestRate . 我有几个具体的实现 无偿付利息 具有名为 ImpliedRate 有适当的签名,以使上述反射起作用。

    使用反射来调用一个甚至不能保证在派生类上存在的静态方法简直是臭不可闻。有更好的方法来处理这个问题吗?

    6 回复  |  直到 12 年前
        1
  •  2
  •   smartcaveman    14 年前

    你应该感到肮脏。这是一些肥皂:

    public static class InterestRateFactories
    {
        static InterestRateFactories()
        {
            _factories = new List<IInterestRateFactory>();
            //  register default factories, although you can also register them elsewhere, like in your ioc setup
        }
        private static readonly List<IInterestRateFactory> _factories;
        public static void RegisterFactory(IInterestRateFactory factory)
        {
            _factories.Add(factory);
        }
        public static T ImpliedRate<T>(double factor, double time, DayCounter dayCounter)
            where T : NonCompoundedInterestRate
        {
            var factory = _factories.FirstOrDefault(x => x.CanCreate(typeof(T), false));
            if (factory == null)
            {
                throw new NotSupportedException("Cannot create a non-compounded implied interest rate of type " + typeof(T).Name);
            }
            return (T)factory.Create(factor, time, dayCounter);
        }
        public static T ImpliedRate<T>(double factor, double time, DayCounter dayCounter, Frequency frequency)
            where T : CompoundedInterestRate
        {
            var factory = _factories.FirstOrDefault(x => x.CanCreate(typeof(T), false));
            if (factory == null)
            {
                throw new NotSupportedException("Cannot create a compounded implied interest rate of type " + typeof(T).Name);
            }
            return (T)factory.Create(factor, time, dayCounter, frequency);
        }
    }
    
    public interface IInterestRateFactory
    {
        bool CanCreate(Type nonCompoundedInterestRateType, bool compounded);
        NonCompoundedInterestRate Create(double factor, double time, DayCounter dayCounter);
        CompoundInterestRate Create(double factor, double time, DayCounter dayCounter, Frequency frequency);
    }
    
        2
  •  1
  •   alexdej    15 年前

    factory模式有一个可测试性优势,但不像您在这里使用的那样。第三种选择是让调用者传递一个工厂类的实例来使用(ImpliedRate方法将位于工厂接口上)。这对于单元测试来说很方便,但对于API的使用者来说可能很麻烦。

        3
  •  1
  •   Dmitry Osinovskiy    15 年前

    public static class InstanceMap
    {
        private static readonly Dictionary<Type,object> instances = 
            new Dictionary<Type,object>();
    
        public static void AddInstance(object instance)
        {
            instances[instance.GetType()] = instance;
        }
    
        public static T GetInstance<T>() { return (T) instances[typeof(T)]; }  
    }
    
    public interface INonCompoundedInterestRate
    {
        INonCompoundedInterestRate ImpliedRate(double factor,
            double time,
            DayCounter dayCounter);
    }
    
    public class MyNonCompoundedInterestRate: INonCompoundedInterestRate
    {
        public INonCompoundedInterestRate ImpliedRate(double factor,
            double time,
            DayCounter dayCounter) { /* do smth*/ }
    
        static MyNonCompoundedInterestRate()
        {
            InstanceMap.AddInstance(new MyNonCompoundedInterestRate());
        } 
    } 
    
    public abstract class InterestRate {
        public static T ImpliedRate<T>(
            double factor,
            double time,
            DayCounter dayCounter
        ) where T : INonCompoundedInterestRate 
        {
            return InstanceMap.GetInstance<T>().
                ImpliedRate(factor, time, dayCounter);
        }
        // ...
    }
    
        4
  •  1
  •   Tim Jarvis    15 年前

    根据我的经验,你只能实例化泛型的无参数构造函数。

    你要达到的目标只能通过反思来实现。

        5
  •  1
  •   Samuel Meacham    15 年前

    在尝试将静态(工厂)方法与继承混合时,总是会遇到冲突。很难得到你想要的多态行为。我也有类似的问题,目前正在使用反射。另一个选项,如前所述,是在不需要静态方法的情况下不使用它。然后,您就可以使用模板方法,或者其他任何能够很好地处理继承的策略。

        6
  •  0
  •   nitzmahone    15 年前