• 装饰器模式和 AOP 面向切片编程(设计模式与开发实践 P15)


    文章目录

    很多时候我们不希望一个类变得非常庞大,生来就包含很多职责。装饰器模式可以动态地给某个对象添加职责,而不会影响从这个类中派生的其他对象

    为什么不用继承解决这个问题呢?如果用继承有可能会创造出数量庞大的子类,而如果把子类的属性变成装饰器,就可以灵活自由地组合了,就像天冷了要穿一件衣服等等

    示例

    从结构上看,Attack 方法进入了一个包装链,先执行火焰技能,再执行了闪电技能

    // 定义游戏角色接口
    interface ICharacter
    {
        void Attack();
    }
    
    // 实现游戏角色类
    class Character : ICharacter
    {
        public void Attack()
        {
            Console.WriteLine("角色进行普通攻击!");
        }
    }
    
    // 装饰器基类
    abstract class CharacterDecorator : ICharacter
    {
        protected ICharacter character;
    
        public CharacterDecorator(ICharacter character)
        {
            this.character = character;
        }
    
        public virtual void Attack()
        {
            character.Attack();
        }
    }
    
    // 具体装饰器类:添加火焰技能
    class FireDecorator : CharacterDecorator
    {
        public FireDecorator(ICharacter character) : base(character)
        {
        }
    
        public override void Attack()
        {
            base.Attack();
            Console.WriteLine("释放火焰技能!");
        }
    }
    
    // 具体装饰器类:添加闪电技能
    class LightningDecorator : CharacterDecorator
    {
        public LightningDecorator(ICharacter character) : base(character)
        {
        }
    
        public override void Attack()
        {
            base.Attack();
            Console.WriteLine("释放闪电技能!");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            // 创建基本角色
            ICharacter character = new Character();
    
            // 添加火焰技能
            character = new FireDecorator(character);
    
            // 添加闪电技能
            character = new LightningDecorator(character);
    
            // 角色进行攻击
            character.Attack();
    
            // 输出结果:
            // 角色进行普通攻击!
            // 释放火焰技能!
            // 释放闪电技能!
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    AOP

    在这里我们使用了 C# 的 PostSharp 包,创建了方法切面监听

    当 Attack 执行时,会引发 OnEntry 和 OnExit 生命周期

    在分离业务代码和数据统计代码中, AOP 十分有效!

    using PostSharp.Aspects;
    using System;
    
    // 日志记录切面
    [Serializable]
    public class LogAspect : OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionArgs args)
        {
            Console.WriteLine($"[Log] Entering {args.Method.Name}");
        }
    
        public override void OnExit(MethodExecutionArgs args)
        {
            Console.WriteLine($"[Log] Exiting {args.Method.Name}");
        }
    }
    
    // 游戏角色类
    public class Character
    {
        [LogAspect] // 应用日志记录切面
        public void Attack()
        {
            Console.WriteLine("Character attacking!");
        }
    }
    
    // 使用 AOP 的游戏示例
    class Program
    {
        static void Main(string[] args)
        {
            Character character = new Character();
            character.Attack();
    
            // 输出结果:
            // [Log] Entering Attack
            // Character attacking!
            // [Log] Exiting Attack
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
  • 相关阅读:
    【项目问题】Vue2和Vue3如何使用Pinia?数据持久化?防止storage被篡改?
    Vue 计算属性
    深入理解final关键字
    PHP+茶叶商城系统 毕业设计-附源码211121
    搬砖日记:关于html的编写规范方式
    Python21天学习挑战赛Day(8)·多线程(threading模块)(应用)
    Linux 环境变量配置的 6 种方法
    设计模式之状态模式
    【Linux成长史】Linux基本指令大全
    SpringBoot项目实战笔记:电脑商城项目实战(SpringBoot+MyBatis+MySQL)
  • 原文地址:https://blog.csdn.net/Littlelumos/article/details/133771652