• C#多态“说来也说”——逻辑层BLL中的多态使用


    本文版权归博客园和作者吴双本人共同所有。欢迎转载,转载和爬虫请注明原文地址  http://www.cnblogs.com/tdws/p/5861842.html

    昨天晚上,有个朋友说学了好久,依然没搞懂多态,让我简单讲解一下。我觉得多态在面向多想的三大特性当中,算是最简单的,最难的是看似容易的封装。在编写面向对象代码时,如何让代码可读性更强,除了变量和方法命名标准外,要做的到一个方法只做一件事情,这样的思想是《代码整洁之道》一书中主要推崇的思想,其实有经验的各位都希望自己看到的代码是简短,可维护,可读性强的,相信大家也都“有幸”遇到过几百上千行的代码,更过分的是有个朋友曾经维护一个上万行的Action,夸张的说,调试并走通逻辑,一次要三天,有的人说这是业务逻辑不断增加所导致,但我认为,在这种情况下,更应该尽量做到一个方法做一件事情。我也不多吐槽了,关于代码整洁,我在大三的时候,就"吐槽"过http://www.cnblogs.com/tdws/p/4674489.html

    封装也不是今天的主题,今天我们要说的是多态,在朋友问我的时候,我给他举了下面这个简短的例子。

    总体概括这个例子来讲就是在基本的三层架构当中,DAL层建两个类AdminDal,UserDal。两个类中,都有增加对象和删除对象地方法,那这个时候,我们应该给两个类抽象出一个父类BaseDal<T>,父类中是他们的公共方法,并且父类需要一个泛型T,这样父类的方法,才能明白你所要添加或者删除的object到底是什么类型的。请看如下代码。虽然两个类的公共方法在父类当中,但是他们自身特有的方法,还是要写在自己的Dal层当中。

    1   public class UserDal: BaseDal<UserEntity>
    2   {
    3         
    4   }
    1   public class AdminDal: BaseDal<AdminEntity>
    2     {
    3         public void Manage()
    4         {
    5             Console.WriteLine("管理员管理网站");
    6         }
    7     }
     1 public class BaseDal<T>
     2     {
     3         public void AddObj(T obj)
     4         {
     5             Console.WriteLine("添加对象成功,对象属于"+obj.GetType().ToString());
     6         }
     7 
     8         public void DeleteObj(T obj)
     9         {
    10             Console.WriteLine("删除对象成功,对象属于"+obj.GetType().ToString());
    11         }
    12 
    13     }

     下面给出逻辑层代码,如果说普通的开发过程当中,你的代码也许是这样的。

     1  public class UserBll 
     2     {
     3         UserDal dal = new UserDal();
     4 
     5         public void Add(UserEntity obj)
     6         {
     7             dal.AddObj(obj);
     8         }
     9 
    10         public void Delete(UserEntity obj)
    11         {
    12             dal.DeleteObj(obj);
    13         }
    14      }
        public class AdminBll 
    { AdminDal dal = new AdminDal(); public void Add(AdminEntity admin) { dal.AddObj(admin); } public void Delete(AdminEntity admin) { dal.DeleteObj(admin); } public void Manage() { dal.Manage(); } }

    也就是在各自的逻辑层当中,调用dal层。这个时候你又看到依然有这么多重复的代码,是不是应该再次封装成一个BaseBll<T>呢。答案是肯定的,但是问题又来了,在封装父类的过程中,你会发现,这个dal的对象怎么封装呢?这就是用到多态的关键点。下面看一下BaseBll.cs的代码。

     public abstract class BaseBll<T> where T:class, new()
        {
            public BaseDal<T> currentDal;
    
            public BaseBll()
            {
                SetCurrentDal();
            }
    
            public abstract void SetCurrentDal();
    
    
            public void BaseAdd(T obj)
            {
                currentDal.AddObj(obj);
            }
    
            public void BaseDelete(T obj)
            {
                currentDal.DeleteObj(obj);
            }
    
        }

    我给了一个抽象的基类,并且给出抽象的SetCurrentDal的抽象方法定义。该方法用于设置当前类的currentDal到底是adminDal还是userDal。我们在构造函数中调用SetCurrentDal这个抽象方法,为什么在构造函数中调用的原因是,当实例化子类对象时,一定是首先进入其父类的构造函数。当子类AdminBll和UserBll继承BaseBll<T>的时候,必须重写抽象方法,并且为BaseDal<T> currentDal对象设置实际的值。我先给出子类的代码

     1 public class AdminBll : BaseBll<AdminEntity>
     2     {
     3         AdminDal dal = new AdminDal();
     4         public AdminBll()
     5         {
     6 
     7         }
     8         public void Manage()
     9         {
    10             new AdminDal().Manage();
    11         }
    12 
    13         public override void SetCurrentDal()
    14         {
    15             currentDal = new AdminDal();
    16         }
    17     }
    1 public class UserBll : BaseBll<UserEntity>
    2     {
    3         public override void SetCurrentDal()
    4         {
    5             base.currentDal = new UserDal();
    6         }
    7     }

    当实例化子类的对象时,过程为:子类构造函数(不进入)—进入父类构造函数—父类构造内部调用子类重写的SetCurrentDal(当前多态的currentDal到底是谁的实例)—父类构造执行完毕(设置currentDal完成)—子类构造函数。这就是抽象方法实现的多态。

    下面在UI层调用一下,看看结果:

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             AdminBll adminBll = new AdminBll();
     6             AdminEntity admin = new AdminEntity() {AdminName="吴双",AdminPwd="123" };
     7             adminBll.Manage();
     8             adminBll.BaseAdd(admin);
     9             Console.ReadKey();
    10         }
    11     }

    输出结果:

    在开发的过程中,也许你会有很多实体类,每个实体类都有各自的增删改查等其他共有方法,基于这样的情况,我们就需要手段来将其封装。为什么在逻辑层使用了多态,原因就是我们封装父类的时候,不确定当前的currentDal到底是adminDal还是userDal还是xxxDal。为了封装出基类,这个多态的对象就必不可少了。

    当然在实际当中,如果你是写原生sql,这样封装的确不容易,各种拼接sql。但如果说你用ORM框架,EF,Dapper之类的,这个方法真的是必不可少的,你可能再加上接口层,加上工作单元,创建对象非new,使用抽象工厂,依赖注入等。无论怎样,这一层的多态一定能用到,只是创建对象稍作修改。

    下一阶段也打算进行后台架构搭建分享,MVC WebApi+EF/Dapper+工作单元+抽象工厂/依赖注入Autofac+AutoMapper+日志组件等。

    我也曾多次在项目中搭建此类框架,在缓存提高性能,处理高并发,应用服务器集群,缓存集群,队列集群等方面,本次也会加入到分享当中。

    如果今天的点滴分享,对您有点滴帮助,请点赞支持,也为自己的进步点赞。

    点击下方关注,我们共同进步。

  • 相关阅读:
    OpenCV人脸识别的原理 .
    图像特征提取三大法宝:HOG特征,LBP特征,Haar特征
    Qt开发者关于QThread的咆哮——你们都用错了
    Qt 线程基础(QThread、QtConcurrent等)
    [saiku] 在 Tomcat 下部署 saiku
    [saiku] 免登陆进入管理后台
    [saiku] 简化/汉化/设置默认页
    [saiku] schema文件分析
    [saiku] 通过管理台配置用户、schema和数据源
    [saiku] 简介、下载、安装和教程
  • 原文地址:https://www.cnblogs.com/tdws/p/5861842.html
Copyright © 2020-2023  润新知