• 单实例使用探讨


    单例模式就是保证在整个应用程序的生命周期中,在任何时刻,被指定的类只有一个实例,并为客户程序提供一个获取该实例的全局访问点。

    一般使用情况:

            private static readonly object _lockObj = new object();
            private static TargetObject_instance;
    
            /// <summary>
            /// Get 唯一实例
            /// </summary>
            public static TargetObject Instance
            {
                get
                {
                    if (_instance == null)
                    {
                        lock (_lockObj)
                        {
                            if (_instance == null)
                                _instance = new TargetObject();
                        }
                    }
    
                    return _instance;
                }
            }

    这样就能保证在多线程模式下,只能使用一个实例了。

    但是这样子不便于拓展,每次新增一个类就要多加一个单实例,很不方便,于是就想到了原先介绍使用的MEF,把每个单实例都看成是一个插件使用,标记后,然后初始化的时候,实例化这些实例,放到相对应的容器中。对应用层只提供从容器中捞取的实例。

    想法了然后就是实践了:

    1 定义单实例的Attribute

        [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
        public class PartAttribute : Attribute
        {
        }

    2 单实例中初始化后,可能需要处理的事件,因为单实例作为插件使用,一般都是使用无参的构造函数,进行反射实例,必然有些属性无法正常加载,必须要读取配置,或者进行其他处理,所以就要执行单实例类中初始化的事件,这样就需要单独标记MethodAttribute了以区分各类方法,因此第二件事定义MethodAttribute。

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
        public sealed class PartActivationMethodAttribute : Attribute
        {
        }

    3 定义容器,存放各类单实例。

    public sealed class PartContainer
        {
             internal IDictionary<Type, PartMetadata> PartInformation { get; set; }
             public void Initialize(IEnumerable<Assembly> partAssemblies)
            {
             }
    
            public void Activate()
            {
             }
        }

    4定义初始化方法,查找已标记PartAttribute的Assembly

    public void Initialize(IEnumerable<Assembly> partAssemblies)
            {
                var partInformation = from asm in partAssemblies
                                      from type in asm.GetTypes()
                                      where type.IsDefined(typeof(PartAttribute), false)
                                      select new
                                      {
                                          Type = type,
                                          Metadata = PartMetadata.GetPartMetadata(type)
                                      };
                PartInformation = partInformation.ToDictionary(p => p.Type, p => p.Metadata);
    
            }

    5定义激活方法,调用已标记MethodAttribute的Method

    public void Activate(IPartActivationContext configuration = null)
            {
                // 整理可以激活的插件类型
                var activePartsInfomation = new Dictionary<Type, PartMetadata>();
                foreach (var partInfo in PartInformation)
                {
                    var type = partInfo.Key;
                    var metadata = partInfo.Value;
                    if (configuration == null || configuration.IsPartEnabled(type, metadata))
                    {
                        activePartsInfomation[type] = metadata;
                    }
                }
    
                // 激活插件
                ActiveParts.ForEach(p => OperateActivation<PartActivationMethodAttribute>(p));
            }
    
    private void OperateActivation<OperationType>(object partInstance)
            {
                     // 根据Attribute找到方法
                var methodInfo = partInstance.GetType()
                    .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                    .Where(m => m.IsDefined(typeof(OperationType), false))
                    .ToArray();
    
                if (methodInfo.Length == 0)
                    return;
    
                if (methodInfo.Length != 1)
                    throw new PartException(string.Format("重复的部件{0}方法", operationName));
    
                var activationMethod = methodInfo[0];
                var methodParameters = activationMethod.GetParameters();
                if (methodParameters != null && methodParameters.Length != 0)
                    throw new PartException(string.Format("部件{0}方法不应该包含任何参数", operationName));
                methodInfo[0].Invoke(partInstance, null);
            }

    然后就可以在目标实力类中使用了:

        [Part]
        internal class TargetObject : ITargetObject 
        {
             [PartActivationMethod]
            private void Initialize()
            {
            }
        }

    使用顺序:

    定义一个PartContainer partContainer

    调用partContainer.Initialize(targetObjectAssemblie);

    调用partContainer.Activate();

    最后就能在partContainer.ActiveParts中获取自己想要的Targerobject实例了。

  • 相关阅读:
    Android之ToolBar的使用
    Android之 RecyclerView,CardView 详解和相对应的上拉刷新下拉加载
    Andorid 之日历控件,可左右滑动,包含公历,农历,节假日等
    Docker技术入门与实战 第二版-学习笔记-4-Dockerfile外其他生成镜像的方法
    Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解
    Docker技术入门与实战 第二版-学习笔记-2-镜像构建
    Docker技术入门与实战 第二版-学习笔记-1-镜像
    docker官方文档学习-1-Docker for mac安装配置
    vagrant up下载box慢的解决办法
    主机ping不通virtualbox虚拟机的解决办法
  • 原文地址:https://www.cnblogs.com/gavinhuang/p/3548127.html
Copyright © 2020-2023  润新知