设计开篇

Posted Skyven

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计开篇相关的知识,希望对你有一定的参考价值。

1 设计模式

   类是我们面向对象编程的承载工具,可以说是面向对象的起点。
   设计模式,这种算面向对象的进化。按照gof设计模式的分类
   设计模式分为:创建型,结构型,行为型。
   其中创建型主要和类的创建有关
   结构性组织扩展类和类之间的关系
   行为型主要扩展的类的访问
   这三个对应到类上
   创建型模式对应的是构造函数
   结构型对应的是类的属性
   行为型对应类的方法
   就想我们以前学数学中很多证明题,都源自最基本的定理,面向对象编程也有类似的地方
   设计模式就是类最基本功能的一个进化

 


 

2.依赖注入    

  相信大家对Ioc(依赖注入)肯定不陌生,Ioc主要遵循设计原则中的依赖倒置原则,  

  但是假设我们不要把这个东西提升到设计的高度,只看它的功能就会发现,   Ioc创建类正好就是控制类的构造函数,和设计模式中创建型模式有关,  

  例如创建型模式中单例模式用ioc生命周期管理可以达到同样的效果,

  这里以Unity为例,Untiy支持child容器。利用child容器,我们可以在运行时提供更多动态创建的内容。

  我们以asp.net mvc为例,我们可以在session初始化的时候根据不同用户注入不同接口的实现。

  例如我们可以在repository中注入一个默认的规约,当不同用户登录   我们可以将用户对数据的访问权限形成一个规约,

  注册到child容器中,然后在controller激活的时候使用当前session的子容器来激活controller。

  在这里使用例子中,Ioc又实现了类似factory,甚至是building模式的功能(这个例子会在后面的文章中给大家展现具体的实现).

 


 

3.抽象的维度  

  多态是代码的下行  

  抽象是代码的下行

  如果B继承自A,C继承自A,那么A称之为B,C这个维度的抽象,B,C称之为A这个维度的变化 A,B,C称之为一个维度的继承关系

  传统的继承解决的是一个维度的变化,如果我们在这个维度上面引入泛型,并且用where限制泛型的行为 或者属性,

  那么就可以用诸如interface<T1,T2,T3>这样,通过组合几个泛型提供多个维度的变化。 此处用泛型扩展的继承有点类似于多继承。

 


 

4.元数据编程(Attribute)

  Attribute在我所使用的元数据编程占有重要位置。

  在asp.net mvc中,ValueProvider,ModuleBinding,Validator,Filter,都使用了元数据编程。

  不谈这个大的我们看一个更小的例子。

  最早在winform中使用DateGrid的时候,我们都是在grid设计器中去设置列的属性,名称,绑定的字段,等等。

  如果我们引入元数据编程,就可以通过在类的属性上加上特性来扩展。

  这样做更便于维护,当你的界面需要修改时,只需要在绑定的类上做修改,修改的地方相对集中,而不用去操作设计器。

 


 

5. 策略工厂

  上面说了很多理论的东西,下面为大家带来点干货。
  首先我们分析一个简单工厂的代码:

  public interface ITest
      {
          void DoSomething();
      }


      public class Test1: ITest
      {
          public void DoSomething()
          {

          }
      }
      public class Test2: ITest
      {
          public void DoSomething()
          {

          }
      }


      public class Factory
      {
          public static ITest Create(string type)
          {
              if (type == "1")
                  return new Test1();
              if (type == "2")
                  return new Test2();
              throw new NotImplementedException();
          }
      }

 

分析简单工厂的弊端  

  1,扩展不方便需要改动create的逻辑  

  2,客户需要知道create的具体逻辑 

  3,创建类型过于单一导致简单工厂类的泛滥  

  4,无法为对象创建提供灵活性,例如构造函数参数  

  5,无法实现运行时扩展

下面我对简单工厂做了一些改造

    public  interface IStrategy
    {
    }

    public interface IGenericsFactory<TStrategy>
        where TStrategy : IStrategy
    {

        /// <summary>
        /// 注册处理策略
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        void Regist(Type type);


        /// <summary>
        /// 获取处理策略
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        TStrategy GetStrategy(string name);

        /// <summary>
        /// 获取所有的处理策略
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        List<string> GetStrategys();
    }

    public class GenericsFactory<TStrategy> : IGenericsFactory<TStrategy>
        where TStrategy : IStrategy
    {
        public GenericsFactory()
        {
            if (_strategys == null)
            {
                _strategys = GetType().Assembly
                        .GetTypes()
                        .Where(item => item.GetInterfaces().Contains(typeof(TStrategy)) || item.IsSubclassOf(typeof(TStrategy)))
                        .Where(item => !item.IsAbstract)
                        .ToDictionary(item =>
                        {
                            var desc = item.GetCustomAttribute<DescriptionAttribute>();
                            return desc != null ? desc.Description : string.Empty;
                        }, item => item);
            }
        }

        protected Dictionary<string, Type> _strategys;

        public void Regist(Type type)
        {
            if (type.GetInterfaces().Contains(typeof(TStrategy)) && type.IsSubclassOf(typeof(TStrategy)))
                throw  new TypeLoadException(string.Format("类型不是从{0},继承",typeof(TStrategy).Name));
            if (_strategys.ContainsKey(MetaDataManager.Attribute.GetDescription(type)))
                return;
            _strategys.Add(MetaDataManager.Attribute.GetDescription(type), type);
        }

        public TStrategy GetStrategy(string name)
        {
            if (!_strategys.ContainsKey(name))
                _strategys.Add(name, typeof(TStrategy));
            return (TStrategy)UnityService.Resolve(_strategys[name]);
        }


        public List<string> GetStrategys()
        {
            return _strategys.Keys.ToList();
        }
    }

 

改造思路
  1,使用将create的类型标记在对应的接口实现上,反射获取子类的特性,如果新增加一个类型只
       需要增加子类,并且在子类添加特性
  2,将所有可用子类的元素据缓存起来,在工厂构造函数中反射所有子类和子类的特性用字典缓存起来
       并且所有可创建的类型暴露给外部
  3,将构造出来的类型做成泛型,并且提供泛型限制,将可构造类型独立出一个维度来变化
  4,通过ioc来动态创建类型
  5,通过提供regist来提供运行时扩展

使用的案例:
  1,SSO登陆,前台用户和后台用户,存放在不同的数据表,数据结构也可能不一样
  2,动态数据权限配置,例如,某个角色只能访问某部分数据 =,>,<等等这些筛选条件的扩展
  3,状态者模式,状态可扩展,可以由界面去选择某种状态对应那种处理方式,
     将处理方式类型放在数据库
  4,责任链模式中节点的扩展和配置
       通过缓存可以直接所有节点,灵活配置节点来实现流程的功能
  5,装饰器的扩展
  可以搭配装饰器模式配置出先用某个装饰后用某个装饰、

 


 

总结:

  上面的这些关于程序设计的一些思考,会在后面的文章中分享一些自己在实际项目中的
  具体案例,请关注后续文章。要想一个架构设计能顺利推广,最简单粗暴的方法就是这个架构能够帮助程序员少些代码。
  下一篇文章将分享一个,全栈式编程的设计,主要应用于后台系统的增删改查,方便程序员更
  快速的处理掉数据的增删改查这部分通用逻辑

 

以上是关于设计开篇的主要内容,如果未能解决你的问题,请参考以下文章

一.设计模式—开篇

设计模式开篇

设计模式开篇

设计模式开篇

设计开篇

设计模式自习室开篇:为什么要有设计模式?