IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> AOP 面向切面编程--WPF Prism.Unity框架中集成的AOP -> 正文阅读

[游戏开发]AOP 面向切面编程--WPF Prism.Unity框架中集成的AOP

概念

1、Aspect-Oriented Programming(面向切面编程),AOP就是对OOP(面向对象编程)的一种功能扩展。
2、需要将核心业务与公共业务分离。

AOP优势

1、将通用功能从业务逻辑中抽离出来,可以省略大量重复代码,有利于代码的操作和维护。
2、模块化开发,降低软件架构的复杂度。

静态AOP

采用装饰器模式或者代理模式实现。

抽象类与实现类:

    public interface IInfoProcessor
    {
        void ReadInfo(string info);
    }
    public class InfoProcessor : IInfoProcessor
    {
        public InfoProcessor()
        {
            Console.WriteLine("InfoProcessor 构造函数执行了");
        }

        public void ReadInfo(string info)
        {
            Console.WriteLine($"主要业务逻辑,接收到一条信息或请求:{info}");
        }
    }

装饰器模式实现:

	/// <summary>
    /// 装饰器模式提供一个AOP功能
    /// </summary>
    public class InfoProcessorDecorator : IInfoProcessor
    {
        private IInfoProcessor _infoProcessor { get; set; }
        public InfoProcessorDecorator(IInfoProcessor infoProcessor)
        {
            this._infoProcessor = infoProcessor;
        }

        public void ReadInfo(string info)
        {
            this.BeforeProceed(info);
            this._infoProcessor.ReadInfo(info);
            this.AfterProceed(info);
        }

        /// <summary>
        /// 业务逻辑之前
        /// </summary>
        /// <param name="user"></param>
        private void BeforeProceed(string info)
        {
            Console.WriteLine("方法执行前");
        }
        /// <summary>
        /// 业务逻辑之后
        /// </summary>
        /// <param name="user"></param>
        private void AfterProceed(string info)
        {
            Console.WriteLine("方法执行后");
        }
    }

上端调用:

        public static void Execute()
        {
            /// 使用了设计模式:装饰模式
            /// 好像功能实现,但是,需要对多个类进行切面的时候,需要创建多个Decorator
            /// 没有通用性
            IInfoProcessor processor = new InfoProcessor();// 实际的业务逻辑
            processor = new InfoProcessorDecorator(processor);
            processor.ReadInfo("哈哈哈");
        }

动态AOP

采用Castle库实现。
AOP有很多方法可以实现,Castle的一个库,用来做动态AOP 。

抽象类与实现类:

    public interface IInfoProcessor
    {
        void ReadInfo(string info);
    }
    public class InfoProcessor : IInfoProcessor
    {
        public InfoProcessor()
        {
            Console.WriteLine("InfoProcessor 构造函数执行了");
        }
        
		/// 注意:被切面的对象方法必须是  virtual
		/// 虚方法在生成代理对象的时候可以被重写
		// 需要把切面逻辑转移到特性里面去
        [Log]
        [Monitor]
        public virtual void ReadInfo(string info)
        {
            Console.WriteLine($"主要业务逻辑,接收到一条信息或请求:{info}");
        }

        [Monitor]
        public virtual void UpdateInfo(string info)
        {

        }
    }

特性类中实现切面逻辑:

    public abstract class AbstractAttributeBase : Attribute
    {
        public abstract void Execute();
    }

    public class LogAttribute : AbstractAttributeBase
    {
        public override void Execute()
        {
            Console.WriteLine("Log 切面逻辑");
        }
    }

    public class MonitorAttribute : AbstractAttributeBase
    {
        public override void Execute()
        {
            Console.WriteLine("Monitor 切面逻辑");
        }
    }

继承接口,实现动态代理,并且将切面转移到特性中去(目前特性只实现了在业务逻辑之前加切面,如果要实现分别在业务逻辑的前后加逻辑,需要在特性中定义Before和After属性来实现;执行顺序可以增加Order属性来实现)

    public class MyInterceptor :StandardInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            if (invocation.MethodInvocationTarget.IsDefined(typeof(AbstractAttributeBase), true))
            {
                foreach (var attr in invocation.MethodInvocationTarget.GetCustomAttributes(typeof(AbstractAttributeBase), true))
                {
                    var log = attr as AbstractAttributeBase;
                    log.Execute();
                }
            }
            //this.PreProceed(invocation);
            invocation.Proceed();// 执行真正的逻辑
            //this.PostProceed(invocation);
            
            // 需要把切面逻辑转移到特性里面去
        }
        public void PreProceed(IInvocation invocation)
        {
            Console.WriteLine("方法执行前");
        }

        public void PostProceed(IInvocation invocation)
        {
            Console.WriteLine("方法执行后");
        }
    }

上端调用:

        public static void Execute()
        {
       		/// 使用代理的方式,针对不同的对象生成实例   生成一个代理对象
            ProxyGenerator generator = new ProxyGenerator();// 代理生成器
            MyInterceptor interceptor = new MyInterceptor();
            InfoProcessor userprocessor = generator.CreateClassProxy<InfoProcessor>(interceptor);               
            userprocessor.ReadInfo("哈哈哈");
        }

动态AOP与IOC整合

手动实现IOC,并在对象创建时整合动态的AOP功能

    public class MyConstructorAttribute : Attribute
    {
    }
    
    public class MyParameterAttribute : Attribute
    {
        public MyParameterAttribute(string shortName = null)
        {
            this.ShortName = shortName;

        }
        public string ShortName { get; set; }
    }
    public interface IMyIoc
    {
        // 注册
        void Register<From, To>(string shortName = null);
        // 获取实例
        From Resolve<From>(string shortName = null);
    }
	/// <summary>
    /// 第三方Ioc容器,需要与业务无关
    /// </summary>
    public class MyIoc : IMyIoc
    {
        Dictionary<string, Type> _containerDic = new Dictionary<string, Type>();

        private string GenerateKey(string abstractName, string shortName) => $"{abstractName}_@$_{shortName}";

        public void Register<AFrom, BTo>(string shortName = null)
        {
            string key = typeof(AFrom).FullName;// 获取抽象的全名称
            key = GenerateKey(key, shortName);// 根据抽象全名称和ShortName组合一个Key【字典的索引】

            if (!_containerDic.ContainsKey(key))
            {
                this._containerDic.Add(key, typeof(BTo));// 把需要创建实例的对象类型保存下来
            }
        }

        /// <summary>
        /// 1、根据抽象类型获取实例类型
        /// 2、初始化构造参数
        /// 3、构造实例
        /// </summary>
        /// <typeparam name="AFrom"></typeparam>
        /// <param name="shortName"></param>
        /// <returns></returns>
        public AFrom Resolve<AFrom>(string shortName = null)
        {
            return (AFrom)ResolveObject(typeof(AFrom), shortName);
        }

        // 依赖N层的时候,需要递归创建对象
        private object ResolveObject(Type abstractType, string shortName = null)
        {
            string key = abstractType.FullName;
            key = GenerateKey(key, shortName);

            if (!_containerDic.ContainsKey(key)) return null;

            Type type = this._containerDic[key];

            // 检查类型的构造函数
            //var ctor = type.GetConstructors()[0];

            // 通过以下方式获取标定了特性的构造函数
            ConstructorInfo constructorInfo =
            type.GetConstructors().FirstOrDefault(c => c.IsDefined(typeof(MyConstructorAttribute), true));
            if (constructorInfo == null)
                // 选择参数最多的构造函数
                constructorInfo = type.GetConstructors().OrderByDescending(c => c.GetParameters().Length).First();


            List<object> paramList = new List<object>();
            // 检查构造函数的参数
            foreach (var param in constructorInfo.GetParameters())
            {
                string paramShortName = "";
                if (param.IsDefined(typeof(MyParameterAttribute), true))
                {
                    paramShortName = ((MyParameterAttribute)param.GetCustomAttribute(typeof(MyParameterAttribute))).ShortName;
                }
                Type paramType = param.ParameterType;//参数的抽象类型
                //string paramKey = GenerateKey(paramType.FullName, "");// 参数对应的类型的Key
                //Type paramInstanceType = this._containerDic[paramKey];// 需要实例化的类型
                //object paramInstance = Activator.CreateInstance(paramInstanceType);// 创建参数实例
                object paramInstance = this.ResolveObject(paramType, paramShortName);// 创建参数实例

                // 参数 也要做构造 函数检查
                paramList.Add(paramInstance);
            }
             获取线程ID
            //int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
            // 反射获取实例 对象
            object instance = Activator.CreateInstance(type, paramList.ToArray());

            // 利用反射获取所有属性,进行注入
            // 属性注入
            foreach (var item in type.GetProperties())
            {
                //item.IsDefined()
                /// 判断是否有特性
                /// 如果有特性就注入   利用ResolveObject方法
            }

            /// 字典-》名称+Type
            /// 进程单例、线程单例
            /// 名称+{Type,线程ID,实例对象列表,实例化类型(枚举:常规、进程单例、线程单例)}
     
     		//动态AOP实现
            ProxyGenerator generator = new ProxyGenerator();// 代理生成器
            MyInterceptor interceptor = new MyInterceptor();
            instance = generator.CreateInterfaceProxyWithTarget(abstractType, instance, interceptor);
            
            return instance;
        }
    }

上端调用:

        static void Main(string[] args)
        {
            IMyIoc myIoc = new MyIoc();
            myIoc.Register<IInfoProcessor, InfoProcessor>();
            IInfoProcessor infoProcessor = myIoc.Resolve<IInfoProcessor>();
            infoProcessor.ReadInfo("Hello AOP");          
        }

Prism.Unity中的AOP

Unity支持三方方式的AOP实现

  • Interface(主流)—适用于BLL业务逻辑层的类,包括接口和实现类
  • VirsualMethod—适用于ViewModel类
  • MarshalByRefObject(单继承,很少用)

需要引用的库:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.19" targetFramework="net48" />
  <package id="Prism.Core" version="8.0.0.1909" targetFramework="net48" />
  <package id="Prism.Unity" version="8.0.0.1909" targetFramework="net48" />
  <package id="Prism.Wpf" version="8.0.0.1909" targetFramework="net48" />
  <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net48" />
  <package id="System.Threading.Tasks.Extensions" version="4.5.2" targetFramework="net48" />
  <package id="Unity.Abstractions" version="5.11.6" targetFramework="net48" />
  <package id="Unity.Configuration" version="5.11.2" targetFramework="net48" />
  <package id="Unity.Container" version="5.11.8" targetFramework="net48" />
  <package id="Unity.Interception" version="5.11.1" targetFramework="net48" />
  <package id="Unity.Interception.Configuration" version="5.11.1" targetFramework="net48" />
</packages>

在这里插入图片描述
定义特性和切面

    public class LogHander : ICallHandler
    {
        public int Order { get; set; }// 执行顺序

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.WriteLine("LogHander方法执行前");

            IMethodReturn methodReturn = getNext().Invoke(input, getNext);

            Console.WriteLine("LogHander方法执行后");

            /// 主要业务逻辑
            /// 还有另外一个切面的话,需要把当前执行过的主业务逻辑传下去
            return methodReturn;

        }
    }

    public class MonitorHandler : ICallHandler
    {
        public int Order { get; set; }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.WriteLine("MonitorHandler方法执行前");

            IMethodReturn methodReturn = getNext().Invoke(input, getNext);

            Console.WriteLine("MonitorHandler方法执行后");

            return methodReturn;
        }
    }
    public class LogHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new LogHander { Order = this.Order };
        }
    }

    public class MonitorHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new MonitorHandler { Order = this.Order };
        }
    }

实现的业务逻辑:

    public interface IMenuBll
    {
        [LogHandlerAttribute(Order = 2)]
        [MonitorHandler(Order = 1)]
        void GetMenus();
    }

    public class MenuBll : IMenuBll
    {
        public void GetMenus()
        {
            Console.WriteLine("获取了系统菜单=============");
        }
    }

1、代码配置AOP

        protected override Window CreateShell()
        {
            /// 使用的容器:Unity
            IUnityContainer unityContainer = Container.Resolve<IUnityContainer>();
            // 代码处理   添加一个扩展,扩展用来选择容器,创建对象的时候考虑一下切面
            unityContainer.AddNewExtension<Interception>().RegisterType<IMenuBll, MenuBll>();
            unityContainer.Configure<Interception>().SetInterceptorFor<IMenuBll>(new InterfaceInterceptor());
            
            unityContainer.Resolve<IMenuBll>().GetMenus();
            
            return Container.Resolve<MainWindow>();
        }

2、配置文件配置AOP

Unity.config配置文件

<configuration>
	<configSections>
		<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
	</configSections>
	<unity>
		<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
		<containers>
			<container name="aopContainer">
				<extension type="Interception"/>
				<register type="My.PrismLesson.Project.BLL.IMenuBll,My.PrismLesson.Project" mapTo="My.PrismLesson.Project.BLL.MenuBll,My.PrismLesson.Project">
					<interceptor type="InterfaceInterceptor"/>
					<interceptionBehavior type="My.PrismLesson.Project.Behavior.LogBeforeBehavior, My.PrismLesson.Project"/>
				</register>
				<register type="My.PrismLesson.Project.ViewModels.LoginWindowViewModel,My.PrismLesson.Project">
					<interceptor type="VirtualMethodInterceptor"/>
					<interceptionBehavior type="My.PrismLesson.Project.Behavior.LogBeforeBehavior, My.PrismLesson.Project"/>
				</register>
				<!--Mash-->
			</container>
		</containers>
	</unity>
</configuration>

需要配置interceptionBehavior节点

    public class LogBeforeBehavior : IInterceptionBehavior
    {
        public bool WillExecute => true;

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            MethodInfo methodInfo = input.Target.GetType().GetMethod(input.MethodBase.Name);
			
			//相关的逻辑也可以改成特性中执行,上面的MethodInfo可以获取相应的特性 
            Console.WriteLine("LogBeforeBehavior方法执行前");

            IMethodReturn methodReturn = getNext().Invoke(input, getNext);

            Console.WriteLine("LogBeforeBehavior方法执行后");

            return methodReturn;
        }
    }
        protected override Window CreateShell()
        {
            /// 使用的容器:Unity
            IUnityContainer unityContainer = Container.Resolve<IUnityContainer>();

            // 配置文件
            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
            fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "UnityConfig\\Unity.Config");
            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
            UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
            configSection.Configure(unityContainer, "aopContainer");

            unityContainer.Resolve<IMenuBll>().GetMenus();
            
            return Container.Resolve<MainWindow>();
        }


3、ViewModel层实现AOP

以上的例子都是针对BLL(业务逻辑层)实现的AOP,只要ViewModel是通过IOC容器来实例化的,那么同样可以对ViewModel来实现AOP的功能。

ViewModel中要加切面的业务逻辑函数要为虚方法(virtual)

    public class LoginWindowViewModel
    {
        public LoginWindowViewModel(Prism.Regions.IRegionManager region)
        {
            /// 如果VM不是由UnityContainer创建的,Region就不可能注入
        }
        private DelegateCommand<Window> _loginCommand;

        public DelegateCommand<Window> LoginCommand
        {
            get
            {
                if (_loginCommand == null)
                    _loginCommand = new DelegateCommand<Window>((w) =>
                    {
                        DoLogin();
                    });
                return _loginCommand;
            }
            set { _loginCommand = value; }
        }

        /// <summary>
        /// 这个方法要为虚方法
        /// </summary>
        public virtual void DoLogin()
        {
            // 登录逻辑执行
            Console.WriteLine("执行登录逻辑");
        }
    }
1)、配置文件配置AOP

Unity.config配置文件,配置interceptor为VirtualMethodInterceptor,采用虚方法注入,所以ViewModel中要加切面的业务逻辑函数要为虚方法(virtual)。

<configuration>
	<configSections>
		<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
	</configSections>
	<unity>
		<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
		<containers>
			<container name="aopContainer">
				<extension type="Interception"/>
				<register type="My.PrismLesson.Project.ViewModels.LoginWindowViewModel,My.PrismLesson.Project">
					<interceptor type="VirtualMethodInterceptor"/>
					<interceptionBehavior type="My.PrismLesson.Project.Behavior.LogBeforeBehavior, My.PrismLesson.Project"/>
				</register>
				<!--Mash-->
			</container>
		</containers>
	</unity>
</configuration>
2)、代码配置AOP
protected override Window CreateShell()
        {
            /// 使用的容器:Unity
            IUnityContainer unityContainer = Container.Resolve<IUnityContainer>();

            // VM也可以进行代码的方式处理    实操
            // 实战使用Prism -》Unity容器-》日志利用AOP的方式处理  业务逻辑的时候不用管一些公共逻辑
            unityContainer.RegisterType<LoginWindowViewModel>(new Interceptor<VirtualMethodInterceptor>(),new InterceptionBehavior<LogBeforeBehavior>());

            return Container.Resolve<MainWindow>();
        }
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 12:16:13  更:2021-09-03 12:16:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/31 1:07:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码