• 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));
            }
        }

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

  • 相关阅读:
    Oracle 基本命令
    一个完整的创建用户,创建表空间,授权建表过程
    jQueryMobile之Popup
    data-theme 几种值的样式
    jQueryMobile之listview
    jQueryMobile之弹出对话框
    android EditText内嵌图片
    css 盒子模型
    kms可用激活服务器地址|kms可用激活服务器分享
    本地配置DNS服务器(MAC版)
  • 原文地址:https://www.cnblogs.com/wangchuang/p/2988759.html
Copyright © 2020-2023  润新知