Builder模式加特性

其实这种设计思想也来源于生活,比如生活中,我们在淘宝上买哥电脑桌,我们要组装它,这类产品都有一个共同点就是会把零件上标好标志

1.定义在指导属性

创建特性类

 /// <summary>
    /// 指导每个具体类型BuildPart过程目标方法和执行情况的属性
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public sealed class BuildStepAttribute : Attribute
    {
        int sequence;
        int times;

        public BuildStepAttribute(int sequence, int times)
        {
            if ((sequence <= 0) || (times <= 0))
                throw new ArgumentOutOfRangeException();
            this.sequence = sequence;
            this.times = times;
        }
        public BuildStepAttribute(int sequence) : this(sequence, 1) { }

        /// <summary>
        /// 执行的次序
        /// </summary>
        public int Sequence { get { return this.sequence; } }

        /// <summary>
        /// 执行的次数
        /// </summary>
        public int Times { get { return this.times; } }
    }

2.通过反射获取执行步骤的工具类型

 public class BuildStep
    {
        public MethodInfo Method { get; set; }
        public int Times { get; set; }
        public int Sequence { get; set; }
    }
  /// <summary>
    /// 通过反射获得某个类型相关BuildPart()步骤指导信息的工具类型
    /// </summary>
    public class BuilderStepDiscovery
    {
        /// <summary>
        /// 缓冲已经解析过的类型信息
        /// </summary>
        static IDictionary<Type, IEnumerable<BuildStep>> cache =
            new Dictionary<Type, IEnumerable<BuildStep>>();

        /// <summary>
        /// 登记那些已经认定没有Build Step 属性的类型
        /// </summary>
        static IList<Type> errorCache = new List<Type>();

        /// <summary>
        /// 借助反射获得类型 T 所需执行BuildPart()的自动发现机制
在.NET 4.0(当然也包括4.0以前的版本)下,用反射判断某个方法是否运用了自定义Attribute时,可以通过调用MethodInfo的IsDefined()方法进行确认。
/// </summary> /// <returns></returns> public IEnumerable<BuildStep> DiscoveryBuildSteps(Type type) { if (type == null) throw new ArgumentNullException("type"); if (errorCache.Contains(type)) return null; if (!cache.ContainsKey(type)) { var aType = typeof(BuildStepAttribute); var methods = from item in (from method in type.GetMethods() where method.IsDefined(aType, false) select new { M = method, A = (BuildStepAttribute)method.GetCustomAttributes(aType, false).First() } )orderby item.A.Sequence select new BuildStep { Method = item.M, Times = item.A.Times, Sequence = item.A.Sequence }; if (methods.Count() == 0) { errorCache.Add(type); // register invalidate type return null; } else { cache.Add(type, methods); // register validate type return methods; } } else return cache[type]; } }

3.依据标签装配过程

反射中借助linq获取每个执行步骤信息的查询

 public interface IBuilder<T> where T : class, new()
    {
        T BuildUp();
    }

    public class Builder<T> : IBuilder<T>where T : class, new()
    {
        public virtual T BuildUp()
        {
            var steps = new BuilderStepDiscovery().DiscoveryBuildSteps(typeof(T));
            if (steps == null) return new T(); // 没有BuildPart步骤,退化为Factory模式
            var target = new T();
            foreach (var step in steps)
                for (var i = 0; i < step.Times; i++)
                    step.Method.Invoke(target, null);
            return target;
        }
    }

测试

 [TestClass]
    public class AttributedBuilderFixture
    {
        #region 采用BuildStep定义装配过程的测试类型

        /// <summary>
        /// 用于显示测试结果的委托
        /// </summary>
        /// <remarks>
        ///     Action<string>是实际处理Build Step操作内容的委托
        /// </remarks>
        static Action<string, Action<string>> buildPartHandler = (x, y) =>
        {
            Trace.WriteLine("add " + x);
            y(x);
        };

        class Car
        {
            public IList<string> Parts { get; private set; }
            public Car(){Parts = new List<string>();}

            /// <summary>
            /// 为汽车添加轮胎
            /// </summary>
            /// <remarks>
            ///     Attributed Builder第二个执行的Setp
            ///     执行4次,即为每辆汽车装配增加4个轮胎
            /// </remarks>
            [BuildStep(2, 4)]
            public void AddWheel() { buildPartHandler("wheel", Parts.Add); }

            /// <summary>
            /// 为汽车装配引擎
            /// </summary>
            /// <remarks>
            ///     没有通过Attribute标注的内容,因此不会被Attributed Builder执行
            /// </remarks>
            public void AddEngine() { buildPartHandler("engine", Parts.Add); }

            /// <summary>
            /// 为汽车装配车身
            /// </summary>
            /// <remarks>
            ///     Attributed Builder第一个执行的Setp
            ///     执行1次,即为每辆汽车装配增加1个车身
            /// </remarks>
            [BuildStep(1)]
            public void AddBody() { buildPartHandler("body", Parts.Add); }
        }

        class Computer
        {
            public string Bus { get; private set; }
            public string Monitor { get; private set; }
            public string Disk { get; private set; }
            public string Memory { get; private set; }
            public string Keyboard { get; private set; }
            public string Mouse { get; private set; }

            /// <summary>
            /// 缓存Computer类型的所有Property
            /// </summary>
            static PropertyInfo[] properties = typeof (Computer).GetProperties();

            /// <summary>
            /// 获得Computer类型指定名称Property的Setter方法委托
            /// </summary>
            /// <param name="target">Computer类型实例</param>
            /// <param name="name">Property名称</param>
            /// <returns>指定名称Property的Setter方法委托</returns>
            static Action<string> GetSetter(Computer target, string name)
            {
                var property = properties.Where(x => string.Equals(x.Name, name)).FirstOrDefault();
                return x => property.SetValue(target, x, null);
            }

            [BuildStep(1)]
            public void LayoutBus()
            {
                buildPartHandler("bus", GetSetter(this, "Bus"));
            }

            [BuildStep(2)]
            public void AddDiskAndMemory()
            {
                buildPartHandler("disk", GetSetter(this, "Disk"));
                buildPartHandler("16G memory", GetSetter(this, "Memory"));
            }

            [BuildStep(3)]
            public void AddUserInputDevice()
            {
                buildPartHandler("USB mouse", GetSetter(this, "Mouse"));
                buildPartHandler("keyboard", GetSetter(this, "Keyboard"));
            }

            [BuildStep(4)]
            public void ConnectMonitor()
            {
                buildPartHandler("monitor", GetSetter(this, "Monitor"));
            }
        }

        #endregion

        [TestMethod]
        public void BuildComputerByAttributeDirection()
        {
            Trace.WriteLine("\nassembly computer");
            var computer = new Computer();
            Assert.IsNull(computer.Keyboard);
            Assert.IsNull(computer.Memory);
            computer = new Builder<Computer>().BuildUp();
            Assert.IsNotNull(computer.Bus);
            Assert.IsNotNull(computer.Monitor);
            Assert.IsNotNull(computer.Disk);
            Assert.IsNotNull(computer.Memory);
            Assert.IsNotNull(computer.Keyboard);
            Assert.IsNotNull(computer.Mouse);
        }

        [TestMethod]
        public void BuildCarByAttributeDirection()
        {
            Trace.WriteLine("build car");
            var car = new Builder<Car>().BuildUp();
            Assert.IsNotNull(car);
            Assert.IsFalse(car.Parts.Contains("engine")); // 不会被执行的内容
            Assert.AreEqual<string>("body", car.Parts.ElementAt(0));
            for (var i = 1; i <= 4; i++)
                Assert.AreEqual<string>("wheel", car.Parts.ElementAt(i));
        }
    }

 有点抽象,有点小难,表示没理解,做个标记,改天再续

原文地址:https://www.cnblogs.com/wangchuang/p/2988759.html