浅谈petshop4.0(一)

逻辑层根据参数调用工厂类中的一个函数,返回这个对象,但是是接口引用的对象,逻辑层在接收的时候也是一个接口引用对象来接收,可见工厂类和逻辑层都引用了接口,数据访问层是引用了接口,所以定义了接口中的函数,返回的数据不是接口类型的

【Model】:
PetShop.Model.ItemInfo中定义相对于数据库表字段的私有属性和公有属性,和一个默认构造函数,和一个含有全部属性的构造函数;

 


【IDAL】:
using PetShop.Model;
所以在 PetShop.IDAL.ITem中就定义了两个接口,实现实体操作和实体内容分离
public interface IItem
{
 IList<ItemInfo> GetItemsByProduct(string productId); 查询 items通过 productId
 ItemInfo GetItem(string itemId);
}

 


【BLL】:
///PetShop.BLL.Item类只有两个方法:这里有个疑问"#####为什么不直接返回一个"类型"而是一个"接口"呢?####"
这个问题已经解决,这里是返回一个借口对象引用,作用是实现统一访问(即统一接口,可以随意指向实现了该接口的类的实例),即对个继承了某个接口的类,当实例化后产生了不同的对象,当要调用某个对象的那个继承了的接口中的那个方法的时候就只要申明一个接口对象然后指向这个类的对象上,然后直接调用这个接口对象引用的接口中的方法即可,就为这个对象的这个方法,要是执行其他对象的接口中的方法,那么就只要把这个接口对象引用为这个对象即可,这里要把接口引用对象指向那个对象是要我们自己动态去写的,假如利用反射的话我们就可以更快的,更灵活的引用哪个对象的那个继承了接口的方法,下面的petshop在实例化哪个数据库的数据库访问层类就是用的这个方法,太妙了,就是在用反射动态实例化一个对象后自动的作为这个接口的引用。
using PetShop.Model;
using PetShop.IDAL;
private static readonly IItem dal = PetShop.DALFactory.DataAccess.CreateItem();
public IList<ItemInfo> GetItemsByProduct(string productId)

 if(string.IsNullOrEmpty(productId))
       return new List<ItemInfo>();
 return dal.GetItemsByProduct(productId);
}
public ItemInfo GetItem(string itemId)
{
        if (string.IsNullOrEmpty(itemId))
            return null;
        return dal.GetItem(itemId);
}

 

【DALFactory】:IItem(继承自接口)///作用是系统该实例化哪个数据访问层的类,不同的数据库有不同的数据访问层的类
using System.Reflection;
using System.Configuration;//配置文件得到path
//应用反射得到实例,然后转换为各个模块的"接口"类型返回给逻辑层
 public static PetShop.IDAL.IItem CreateItem()
{
      string className = path + ".Item";//这里的path应该为一个全局变量,而对应一个用户一般为一种数据库,所以其配置文件中就为该种数据库所对应的路径
      return (PetShop.IDAL.IItem)Assembly.Load(path).CreateInstance(className);//在这里就把某种数据访问层的对象(当然这个对象是事先继承了那个接口的)变为接口的引用,即接口的引用对象,这个对象就只有两个方法,而调用的这两个方法是属于这个这种类型的数据库的【参考下petshop4.0接口的作用这边文章】
}
这里是一种重要的思想吧:
    首先两点要明白,一,每种数据库的数据访问层类都继承了这个接口,二,当某个用户在使用这个系统的时候他的数据库应该是唯一的,所以配置中的path这个全局变量从配置文件中获得的值也是唯一的,即现在用的是一种数据库,然后通过反射就实例化了属于这种数据库的数据访问层类的对象:Assembly.Load(path).CreateInstance(className),然而每个数据库访问类的这个函数返回的不是当前这个类的对象,返回的是这个类继承了的接口的一个引用(但是这个接口对象的引用不是一个实例化的接口对象,接口也不能被实例化,意思是这个接口对像是这个接口的一个引用对象,即他指拥有这个接口中定义的方法,没有其他方法,假设尽管这个类除了继承了这个接口外还自己定义了一些方法,则这些方法不能在这个接口对象中体现出来)
    这里有一点,即不同的数据库的数据库访问层类实例化后所得到的接口对象多调用的接口方法就是相对应的这种数据库的数据库访问层的类中的方法,而不要另外附加的代码来指出。如:若是orlcal数据库,那么这个接口引用对象所调用的接口函数就为orlcal数据库的数据库访问层类的方法,之后一直都是,即不要写一个函数用if()来判断如果接口引用为orlcal类型的对象那么这个接口引用对象以后调用里面的方法的时候就为orlcal这个数据库中的数据库访问层中的方法,然后再来一个else又来判断若是sql类型的就怎么怎么样,不用,这个接口是自动的,马上的,也就是(PetShop.IDAL.IItem)Assembly.Load(path).CreateInstance(className)这行代码就自动的切换到相对应的类的方法中,

 

【DAL】:
using PetShop.Model;
using PetShop.IDAL;接口
using PetShop.DBUtility;///SqlHelp.cs
public IList<ItemInfo> GetItemsByProduct(string productId){}
public ItemInfo GetItem(string itemId) {}

 

在数据访问层中继承接口(可以说这个接口是为了数据访问层而设置的,不是因为逻辑层的需要才设置的)的优点是,当数据访问层的数据库变成了其他数据库只要改下数据访问层就可以了,而不用去修改逻辑层的代码,可以说数据访问层的修改对于业务逻辑层来说的斑点关系都没有,对于上面为什么要使用返回接口而不是类,在逻辑层我们要的是接口定义的方法所得到的结果,所以我们只返回能得到方法结果的借口而不是整个的类;有了IDAL保证了系统的可扩展性,同时也保证了数据库的可移植性。在PetShop中,可以支持SQL Server和Oracle,那么它们具体的实现就分别放在两个不同的模块SQLServerDAL、OracleDAL中

 

【新颖的解释】:##########################################################

1.在PetShop中,系统需要处理的数据库对象分为两类:一是数据实体,即实体表,第二类数据库对象则是数据的业务逻辑对象。这里所指的业务逻辑,并非业务逻辑层意义上的领域(domain)业务逻辑(从这个意义上,我更倾向于将业务逻辑层称为“领域逻辑层”),一般意义上说,这些业务逻辑即为基本的数据库操作,包括Select,Insert,Update和Delete。由于这些业务逻辑对象,仅具有行为而与数据无关,因此它们均被抽象为一个单独的接口模块IDAL(即这个接口就是一种业务逻辑,数据逻辑中的所有操作方法都定义为方法);将数据实体与相关的数据库操作分离出来,符合面向对象的精神。首先,它体现了“职责分离”的原则。将数据实体与其行为分开

2.由于sql和oracal用是访问数据看语言不大一样,所以在数据访问层最好都用存储过程,因为把sql写在数据访问层时,当把数据库改成是oracal,那就要改了,这样不利于数据库的移植。


3.在PetShop中,要创建的数据对象包括Order,Product,Category,Inventory,Item。(这些都是一个一个我们处理的模块类)在前面的设计中,这些对象的业务逻辑(是只这个模块需要的一些功能在逻辑层中所要体现出来的一些方法)已经被抽象为对应的接口,而其实现则根据数据库的不同而有所不同。也就是说,[[[[[[创建的对象有多种类别,而每种类别又有不同的实现]]]]]]](记住一个数据库访问层类是一个总类,是不可能实例化的,因为他里面包含了很多的子类,即每个实体对应的数据库访问层类,最后实例化的才是这个具体的类,而不的SQlDAL或者oracalDal这个总类,于是才有了抽象工厂的说法)这是典型的抽象工厂模式的应用场景,而这个抽象工厂的实现是在DALFactory中的,【它是模式加上配置文件,再加上反射】,这种方式很重要。我们可以在web.config文件中,配置好具体的Factory对象的完整的类名,在这里解释下,对于不同数据库的类无非就是路径不一样而类名是一样的,所以我们把路径存储在配置文件中,这样反射根据一个动态的完整的路径就实例化了一个相应的数据库要操作的类。代码如下:


private static readonly string path = ConfigurationManager.AppSettings["WebDAL"];
private static readonly string orderPath = ConfigurationManager.AppSettings["OrdersDAL"];
public static PetShop.IDAL.IItem CreateItem()
{
      string className = path + ".Item";这个classname将实例化为sql数据库所对应的这个类,"item"是类名
      (string className = orderPath + ".Item";这个classname将实例化为oracal数据库所对应的这个类)
      return (PetShop.IDAL.IItem)Assembly.Load(path).CreateInstance(className);
}
可以从上面看出来,配置文件好像只有一个配置出一个不同数据库所对应的完整的路径,除了类名的作用。
其实我们还可以简化这个程序,因为实例化一个类无非只要给它一个类名就可以了,所以我们把上面的这个CreateItem函数进行封装:如下:
我们定义一个通用的类ServiceLocator

public static class ServiceLocator
{
    private static readonly string dalPath = ConfigurationManager.AppSettings[”WebDAL”];
    private static readonly string orderPath = ConfigurationManager.AppSettings[”OrdersDAL”];

    public static object LocateDALObject(string className)
    {
         string fullPath = dalPath + “.” + className;
         return Assembly.Load(dalPath).CreateInstance(fullPath);
    }
    public static object LocateDALOrderObject(string className)
    {
         string fullPath = orderPath + “.” + className;
         return Assembly.Load(orderPath).CreateInstance(fullPath);
    }
}
然后我们的调用类就是
public sealed class DataAccess
{
   public static PetShop.IDAL.IOrder CreateOrder() ///创建一个oracal数据库相对应的类
   {
     return (PetShop.IDAL.IOrder)ServiceLocator. LocateDALOrderObject(”oracal”);
   }
   public static PetShop.IDAL.IOrder Createdalrder() ///创建一个sql数据库相对应的类
   {
     return (PetShop.IDAL.IOrder)ServiceLocator. LocateDALObject(”Order”);
   }
}
通过ServiceLocator,将所有与配置文件相关的namespace值统一管理起来,这有利于各种动态创建对象的管理和未来的维护

其实上面的例子只是对DALFactory进行了更好的封装而已,其实也没什么的

不过看来上面并不是我自己之前一直想的调用每个类都是用反射,而是用哪种数据库所对应的类才要用到动态的实例化一个类,是实例化哪种数据库的类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值