zoukankan      html  css  js  c++  java
  • 复杂业务简单化的一个小技巧

    在复杂系统中,当对业务数据进行“删除”时(一般不允许对业务数据进行删除,只是举例) ,需要根据其它业务数据进行判断如:
      1.已生成出库单不允许删除,
      2.付款单已确认不允许删除,
      3.已经退换货则不允许删除。
      实际业务中可能会更加复杂。
          当出现这种情况时将导致“删除”业务判断会非常多,而且会经常修改,很有可能当其它业务发生变化时需要重新去调整“删除”业务。
    解决方法:为业务数据增加一个中间件“是否可以删除的标识”其它业务发生变化时修改此标识为false  其它业务修改时不能将此标识改为true 删除时只根据此标识做判断,可能会手动修改业务标识(高级操作)
          不能将此标识改为true是因为 改为true需要去做很多验证,为了避免复杂性所以不能修改标识为true。
          如:用户提出需求“自营店,可以修改价格,可以添加赠品,不扣预存款。非自营店,不能改价格,不能加赠品,扣款存款”
                程序设计时最好别把 “自营或非自营”做为判断条件,而将“是否允许修改价格,是否允许添加赠品,是否扣除预存款”做为判断条件,对店铺(业务数据)增加相应的控制开关配置。
                这样可能很好的提高程序扩展性,未来业务发生变化时可以不用修改代码。比如 需要"非自营店可能添加赠品"时。
         对业务数据的控制开关配置可以使用key/value形式通一设计持久化保存,这些开关拒绝和业务数据的查询有联系。
         注意事项:1.如果系统中大量使用开关配置,会经常会开关配置进行修改,需要考虑并发性,防止多个业务同时对相同的控制开发进行修改。
                       2.此类配置不会做为数据检索条件
        
        以上是工作中记录内容,分享相应的处理代码,希望对你们有用
     
    /// <summary>
        /// 数据配置类
        /// </summary>
        public class SmartConfig : BaseEntity
        {
            /// <summary>
            /// 类型
            /// </summary>
            [MaxLength(32)]
            public string Type { get; set; }
            /// <summary>
            /// 类型标识
            /// </summary>
            [MaxLength(32)]
            public string TypeIdentity { get; set; }
            /// <summary>
            /// 时间截
            /// </summary>
            [MaxLength(32)]
            public string Timestamp { get; set; }
            /// <summary>
            /// 配置
            /// </summary>
            public string Config { get; set; }
        }
    View Code

    这是Table对应的实体类,用于数据存储。

     /// <summary>
        /// 业务数据配置类
        /// 请勿直接new这个对象,使用SmartConfigService.Get 方法获取对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <remarks>2014-08-20 ywb 创建</remarks>
        public class Smart<T>
        {
            /// <summary>
            /// 请勿直接new这个对象,使用SmartConfigService.Get 方法获取对象
            /// </summary>
            /// <param name="typeIdentity"></param>
            /// <param name="timestamp"></param>
            /// <param name="config"></param>
            public Smart(string typeIdentity, string timestamp, T config)
            {
                this.Timestamp = timestamp;
                this.Type = typeof(T).Name.Replace("C_", "");
                this.TypeIdentify = typeIdentity;
                this.Config = config;
            }
            /// <summary>
            /// 业务数据类型
            /// </summary>
            public string Type { get; private set; }
            /// <summary>
            /// 业务数据标识
            /// </summary>
            public string TypeIdentify { get; private set; }
            /// <summary>
            /// 时间戳
            /// </summary>
            public string Timestamp { get; private set; }
            /// <summary>
            /// 配置
            /// </summary>
            public T Config { get; private set; }
        }
    View Code

    业务数据配置类

    /// <summary>
        /// 菜 配置
        /// </summary>
        /// <remarks>
        /// 约定命名规则为 前缀“C_ ”+ “业务表名”
        /// 这种方式不太符合规范但是好用,配合VS智能提示写代码方便    
        /// </remarks>
        public class C_Dish
        {
            public C_Dish()
            {
                //在构造函数中设置配置项的默认值
                NeedCooking = true;
                EnabledPrint = true;
                Return = false;
                AllowToCart = true;
            }
            /// <summary>
            /// 需要厨师烹饪
            /// </summary>
            [Description("需要厨师烹饪")]
            public bool NeedCooking { get; set; }
            /// <summary>
            /// 状态为“完成”时可退
            /// </summary>
            [Description("状态“完成”时能退")]
            public bool Return { get; set; }
    
            /// <summary>
            /// 启用打印
            /// </summary>
            [Description("启用打印")]
            public bool EnabledPrint { get; set; }
    
            /// <summary>
            /// 允许顾客点餐
            /// </summary>
            [Description("允许顾客点餐")]
            public bool AllowToCart { get; set; }
            
    
        }
    View Code

    这是具体业务拥有的配置,在构造函数中设置业务数据配置项的默认值

    /// <summary>
        /// 配置Service
        /// </summary>
        public static class SmartConfigService
        {
            /// <summary>
            /// 更新 SySmartConfig
            /// 如果返回false 很可能是并发引起的,需要业务终止执行。
            /// </summary>
            /// <param name="type">业务类型</param>
            /// <param name="typeIdentity">业务类型标识</param>
            /// <param name="config">配置</param>
            /// <param name="timestamp">更新前的时间戳</param>
            /// <param name="newTimestamp">更新后的时间戳</param>
            /// <returns></returns>
            public static bool Update(string type, string typeIdentity, string config, string timestamp, string newTimestamp)
            {
                
                var flag = DB.Wdd.Database.ExecuteSqlCommand("update SmartConfigs set Config={0},Timestamp={1} where Type={2} and TypeIdentity={3} and Timestamp={4}"
                    , config, newTimestamp, type, typeIdentity, timestamp) == 1;
                CacheMemory.Remove(string.Format(CacheKey.Domain_SmartConfig, type, typeIdentity));
                return flag;
    
            }
            /// <summary>
            /// 获取 SySmartConfig 如果数据库中没有,则创建并返回SySmartConfig
            /// </summary>
            /// <param name="type">业务类型</param>
            /// <param name="typeIdentity">业务类型标识</param>
            /// <param name="timestamp">时间戳</param>
            /// <returns></returns>
            public static SmartConfig Get(string type, string typeIdentity, string timestamp)
            {
                var cacheKey = string.Format(CacheKey.Domain_SmartConfig, type, typeIdentity);
                return CacheMemory.Get<SmartConfig>(cacheKey, () =>
                {
                    var config = DB.Wdd.SmartConfigs.FirstOrDefault(p => p.Type == type && p.TypeIdentity == typeIdentity);
                    if (config != null) return config;
    
                    config = new SmartConfig()
                    {
                        Config = string.Empty,
                        Timestamp = timestamp,
                        Type = type,
                        TypeIdentity = typeIdentity
                    };
                    DB.Wdd.AddEntity<SmartConfig>(config);
                    return config;
                }, new TimeSpan(24, 0, 0));
            }
    
            /// <summary>
            /// 保存 业务数据配置
            /// 如果返回false 很可能是并发引起的,需要业务终止执行。
            /// </summary>
            /// <param name="smart">业务数据配置.</param>
            public static bool Save<T>(Smart<T> smart)
            {
                if (smart == null) throw new ArgumentNullException("smart");
                return Update(smart.Type, smart.TypeIdentify, Newtonsoft.Json.JsonConvert.SerializeObject(smart.Config), smart.Timestamp, Timestamp(DateTime.Now));
            }
    
            /// <summary>
            /// 获取 业务数据配置
            /// </summary>
            /// <param name="typeIdentity">业务类型标识.</param>
            public static Smart<T> Get<T>(string typeIdentity)
            {
                var type = typeof(T).Name.Replace("C_", "");
                var smartConfig = Get(type, typeIdentity, Timestamp(DateTime.Now));
                if (string.IsNullOrEmpty(smartConfig.Config)) smartConfig.Config = "{}";
    
                //转换出错异常不处理
                var config = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(smartConfig.Config);
                return new Smart<T>(typeIdentity, smartConfig.Timestamp, config);
            }
    
            /// <summary>
            /// 获取时间戳.
            /// </summary>
            /// <param name="dt">时间.</param>
            /// <returns></returns>
            private static string Timestamp(DateTime dt)
            {
                DateTime dt1 = new DateTime(1970, 1, 1);
                TimeSpan ts = dt - dt1;
                return ts.TotalMilliseconds.ToString();
            }
        }
    View Code

    这是接口层代码实现,开发人员只需要关心以下二个方法

    public static bool Save<T>(Smart<T> smart)

    public static Smart<T> Get<T>(string typeIdentity)

    其它方法不需要关心,可改为private。

    调用代码如下:

                var dish = SmartConfigService.Get<C_Dish>("1");
                dish.Config.NeedCooking = true;
                SmartConfigService.Save(dish);

    保存的时候可以判断一下返回值如果为false,可能是因为并发,应结束业务处理

  • 相关阅读:
    新概念第二册(1)--英语口语听力课1
    外企面试课程(一)---熟悉常见的缩略词
    公司 邮件 翻译 培训 长难句 结课
    workflow
    公司 邮件 翻译 培训 长难句 20
    公司 邮件 翻译 培训 长难句 19
    Engineering Management
    公司 邮件 翻译 培训 长难句 18
    公司 邮件 翻译 培训 长难句 17
    第14.5节 利用浏览器获取的http信息构造Python网页访问的http请求头
  • 原文地址:https://www.cnblogs.com/snryang/p/4875747.html
Copyright © 2011-2022 走看看