C# 反射 策略模式改造 switch case 或者 if else

本文深入讲解策略模式的应用,包括如何将策略模式应用于业务处理中,替代传统的switch-case或if-else结构,以实现代码的扩展性和灵活性。文章详细介绍了策略模式的实现方式,从简单的策略模式到引入上下文的策略模式,再到利用反射创建策略对象,提供了丰富的代码示例。

一、前言

        由于在业务处理上使用了较多的 switch case 或者 if else,使用了策略模式改造下代码,以便后续的扩展,

不应为了设计模式而设计模式,应从具体业务出发,不然只会让代码的复杂度增加

二、何为策略模式

         也叫 政策模式(Policy Pattern)。指的是对象具备某个行为,但是在不同的场景中,该行为有不同的实现算法。比如一个人的交税比率与他的工资有关,不同的工资水平对应不同的税率。

策略模式使用的就是面向对象的继承和多态机制,从而实现同一行为在不同场景下具备不同实现。

策略模式本质:分离算法,选择实现

三、应用策略模式

1)直白写法

public void DoWork(int taskType)
        {
            switch (taskType)
            {
                case (int)TaskType.上传单价:
                    Console.WriteLine("执行上传单价业务");
                    break;
                case (int)TaskType.上传工单:
                    Console.WriteLine("执行上传工单业务");
                    break;
                case (int)TaskType.上传配件:
                    Console.WriteLine("执行上传配件业务");
                    break;
                case (int)TaskType.上传附件:
                    Console.WriteLine("执行上传附件业务");
                    break;
                default:
                    Console.WriteLine("无效任务类型");
                    break;
            }
        }

 2)简单策略模式

截取自  http://my.oschina.net/BreathL/blog/52655

 

2.1)创建策略接口类

/// <summary>
    /// 策略类接口
    /// </summary>
    public interface IStrategy
    {
        void DoStrategyWork();
    }

2.2)创建策略实现类

public class 上传单价 : IStrategy
    {
        public void DoStrategyWork()
        {
            Console.WriteLine("执行上传单价业务");
        }
    }

2.3)创建对外调用类

public class User
    {
        public void StartHere(IStrategy strategy)
        {
            strategy.DoStrategyWork();
        }
    }

2.4)调用

new 一般策略写法.User().StartHere(new InstanceFactory<一般策略写法.IStrategy>().CreateInstanceByEnumName(tType));

3)上下文的引入

上下层调用、交互,往往不是固定不变的,比如调用函数的参数变化、增加方法等

截取自  http://my.oschina.net/BreathL/blog/52655

 

3.1)创建策略抽象类(接口也是可以的,具体业务具体分析)

/// <summary>
    /// 策略类抽象类
    /// </summary>
    public abstract class IStrategy
    {
        public abstract TaskType CommandType { get; }

        public abstract void DoStrategyWork(StrategyContext strategyContext);
    }

3.2)创建策略实现类

public class 上传单价 : IStrategy
    {
        public override TaskType CommandType => TaskType.上传单价;

        public override void DoStrategyWork(StrategyContext strategyContext)
        {
            Console.Write("执行上传单价业务 ");
            Console.WriteLine("我是可变参数:" + strategyContext.pars);
        }
    }

3.3)创建上下文类

通过上下文  进行对应策略算法调用,执行具体实现类的算法,同时写携带业务交互参数

public class StrategyContext
    {
        private IStrategy _strategy;

        #region 可变的上下文参数

        public string pars { get; set; }

        #endregion

        public StrategyContext(IStrategy strategy)
        {
            this._strategy = strategy;
        }

        public void InvokingStrategy()
        {
            this._strategy.DoStrategyWork(this);
        }
    }

3.4)创建对外调用类

public class User
    {
        private StrategyContext strategyContext;

        public User(TaskType taskType, string pars)
        {
            this.strategyContext = new StrategyContext(new InstanceFactory<IStrategy>().CreateInstanceBySubClass(taskType));
            this.strategyContext.pars = pars;
        }

        public void StartHere()
        {
            strategyContext.InvokingStrategy();
        }
    }

3.5)调用

new 上下文策略写法.User(tType, "我是参数").StartHere();

四、反射创建对象

/// <summary>
    /// 利用反射创建具体策略类,并缓存起来
    /// </summary>
    public class InstanceFactory<T> where T : class
    {
        /// <summary>
        /// 一般处理对象缓存
        /// </summary>
        private static Dictionary<TaskType, T> dicCommands = new Dictionary<TaskType, T>();

        /// <summary>
        /// 上下文策略对象缓存
        /// </summary>
        private static Dictionary<TaskType, T> dicContextCommands = new Dictionary<TaskType, T>();
        
        /// <summary>
        /// 根据TaskType 的名称创建类对象
        /// </summary>
        /// <param name="taskType"></param>
        /// <returns></returns>
        public T CreateInstanceByEnumName(TaskType taskType)
        {
            foreach (TaskType cd in Enum.GetValues(typeof(TaskType)))
            {
                if (!dicCommands.Keys.Contains(cd))
                {
                    //(基类)Assembly.Load("当前程序集名称").CreateInstance("命名空间.子类名称"));  
                    T baseCommand = Assembly.Load(typeof(T).Assembly.GetName().Name)
                        .CreateInstance((typeof(T).Namespace + "." + cd)) as T;

                    if (baseCommand != null)
                    {
                        dicCommands.Add(cd, baseCommand);
                    }
                }

            }

            return dicCommands.FirstOrDefault(c => c.Key == taskType).Value;
        }

        /// <summary>
        /// 通过继承关系创建子类
        /// </summary>
        /// <param name="taskType"></param>
        /// <returns></returns>
        public T CreateInstanceBySubClass(TaskType taskType)
        {
            Type objType = typeof(T);
            // 获取此类型所在的程序集
            Assembly assembly = objType.Assembly;
            // 遍历获取此程序集中所有的类
            foreach (Type t in assembly.GetTypes())
            {
                // 是类并且不是抽象类并且继承IBaseCommand
                if (t.IsClass && !t.IsAbstract && t.IsSubclassOf(objType))
                {
                    // 创建策略实例类
                    T command = Activator.CreateInstance(t) as T;

                    var key = (TaskType)Enum.Parse(typeof(TaskType), t.GetProperty("CommandType").DeclaringType.Name);

                    if (command != null && !dicCommands.ContainsKey(key))
                    {
                        dicContextCommands.Add(key, command);
                    }
                }
            }

            return dicContextCommands.FirstOrDefault(c => c.Key == taskType).Value;
        }
    }

五、代码下载

https://github.com/harrylsp/Strategy

六、参考引用

https://my.oschina.net/BreathL/blog/52655

https://blog.youkuaiyun.com/qq_19348391/article/details/84404034

https://blog.youkuaiyun.com/site008/article/details/77947566

<think>好的,用户想知道switch caseif elseif的区别。我需要先回忆这两者的基本概念,然后从多个方面进行比较,比如语法结构、适用场景、性能差异等。 首先,应该解释它们各自的结构。if elseif是条件分支,逐个检查条件;而switch case基于一个表达式的值跳转到对应的case。语法上,if使用布尔表达式,switch用常量表达式。 然后,适用场景的不同。当条件判断是范围或复杂逻辑时,用if更合适;如果是离散的特定值,switch可能更高效。比如,处理枚举或固定值时,switch更清晰。 性能方面,可能要考虑编译器优化。switch有时会被编译成跳转表,效率比多个if判断高,尤其是在case很多的时候。不过现代编译器对if也可能优化,所以这点可能需要说明实际情况不同。 还要提到一些细节,比如switchcase必须是常量,不能重复,且通常需要break,否则会穿透。而if elseif每个条件独立,顺序执行,没有穿透问题。 用户可能是程序员,可能在选择结构时犹豫,或者想优化代码。需要强调可读性和维护性,以及具体使用场景的建议。可能还需要指出在支持的语言中switch的不同特性,比如JavaScript允许字符串,而某些语言如C#有类型限制。 最后,总结两者的区别,帮助用户根据具体情况做选择。确保语言通俗易懂,结构清晰,分点说明。</think>### 1. 基础语法区别 - **`if-elseif` 结构**: ```javascript if (条件1) { // 执行代码块1 } else if (条件2) { // 执行代码块2 } else { // 默认代码块 } ``` - 依赖**布尔表达式**判断(如 `x > 5` 或 `status === "success"`) - 可处理**范围比较**(如 `x < 10`)或**复杂逻辑**(如 `x && y`) - **`switch-case` 结构**: ```javascript switch (表达式) { case 值1: // 执行代码块1 break; case 值2: // 执行代码块2 break; default: // 默认代码块 } ``` - 直接匹配**固定值**(如数字、字符串、枚举) - 需显式使用 `break` 防止代码穿透 --- ### 2. 核心区别对比表 | **特性** | **`if-elseif`** | **`switch-case`** | |-------------------|------------------------------------|------------------------------------| | **判断类型** | 任意布尔表达式 | 固定值的严格匹配 | | **适用场景** | 范围判断、复杂逻辑 | 离散值匹配(如枚举、常量) | | **代码可读性** | 条件复杂时易冗长 | 多分支时更简洁直观 | | **执行机制** | 逐条判断,直到命中条件 | 直接跳转到匹配的 `case` | | **性能优化** | 条件多时可能效率低 | 编译器可能生成跳转表(更快) | | **穿透行为** | 无 | 需手动 `break` 防止穿透 | --- ### 3. 使用场景建议 - **优先 `switch-case`**: - 处理**固定值匹配**(如 HTTP 状态码、菜单选项) - 分支数量**超过 3 个**时(提升可读性) - 例: ```javascript // 根据天气状态显示图标 switch (weather) { case "sunny": 显示太阳图标; break; case "rainy": 显示雨伞图标; break; case "cloudy": 显示云图标; break; } ``` - **优先 `if-elseif`**: - 需要**范围判断**(如 `score >= 90`) - 涉及**复合条件**(如 `age > 18 && isStudent`) - 例: ```javascript if (temperature > 35) { alert("高温预警!"); } else if (temperature < 0) { alert("低温警告!"); } ``` --- ### 4. 底层机制差异 - **`switch-case` 的优化**: - 编译器可能将 `switch` 转换为**跳转表(Jump Table)**,时间复杂度接近 $$O(1)$$ - 例如: ```c // 编译后可能直接通过偏移量跳转 jmp [table + 4*value] ``` - **`if-elseif` 的执行**: - 按顺序检查条件,时间复杂度为 $$O(n)$$ - 例: ```javascript // 若条件多且分布均匀,可能需多次判断 if (x === 1) { ... } else if (x === 100) { ... } // 需要检查前99次失败 ``` --- ### 5. 语言特性差异 - **JavaScript 扩展**: - `switch` 支持字符串和对象(需注意严格相等 `===`) - 例: ```javascript switch (true) { // 利用布尔值匹配 case (x > 10): ... } ``` - **Java/C# 限制**: - `case` 必须是**编译期常量**(如 `case 1:` 合法,`case x:` 非法) - 例: ```java final int MAX = 10; switch (value) { case MAX: ... // 合法(MAX是常量) } ``` --- ### 6. 总结建议 - **可读性优先**:分支多且离散时用 `switch`,逻辑复杂时用 `if` - **性能关键场景**:对密集分支(如解析器、状态机)优先测试 `switch` - **避免滥用**:不要强行用 `switch` 代替 `if` 的范围判断 > 📌 **示例**:解析用户角色权限时: > ```javascript > // 用 switch 更清晰 > switch (user.role) { > case "admin": 加载管理面板; break; > case "editor": 加载编辑功能; break; > default: 限制访问; > } > ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值