• 复杂业务简单化的一个小技巧


    在复杂系统中,当对业务数据进行“删除”时(一般不允许对业务数据进行删除,只是举例) ,需要根据其它业务数据进行判断如:
      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,可能是因为并发,应结束业务处理

  • 相关阅读:
    (CSDN 迁移) jFinal找不到或无法加载主类
    (CSDN迁移) jFinal无法启动_JFinalDemoGenerator问题解决办法
    (CSDN迁移) JAVA多线程实现-可控最大并发数线程池(newFixedThreadPool)
    (CSDN迁移)JAVA多线程实现-单线程化线程池newSingleThreadExecutor
    (CSDN迁移) JAVA多线程实现-实现Runnable接口
    (CSDN迁移)JAVA多线程实现-继承Thread
    (CSDN迁移) html中的rel属性
    通过microtask和macrotask理解Vue.nextTick()的实现
    javascript处理异步的三种方法
    git常用的基本命令
  • 原文地址:https://www.cnblogs.com/snryang/p/4875747.html
Copyright © 2020-2023  润新知