Products.aspx 在前面 petshop学习笔记(2) 已经说明是如何是经过类 Product 的GetProductsByCategory方法进行获取数据的
Product这个类又是怎么来获取数据的?我想慢慢来了解一下!
PetShop采用的是三层结构进行划分各个职能,前面了解的那些是表示层,这一篇是表示层经业务逻辑层来读取数据库的一个示例。典型的三层结构。
PetShop在这里也使用了很多工厂模式,所以要读明白里面的东西也至少要知道这种设计模式,我看了之后还是一头雾水,下面就以我粗鄙的想法自身去了解一下罗.网上也有很多关于这个模式的东西,都写得相关不错。我这里就简化一下罗。
抽象厂工,具体工厂,抽象产品,具体产品,客户端,具体的内容想要理解我之前转的文章里有写到,不例外,product也是使用这种模式去读取数据库的。
一、表示层
Web项目里的Controls文件夹下的ProductsControl.ascx
看他的代码:
protected void PageChanged(object sender, DataGridPageChangedEventArgs e) {
productsList.CurrentPageIndex = e.NewPageIndex;
string categoryKey = Request.QueryString["categoryId"];
Product product = new Product();
productsList.DataSource = product.GetProductsByCategory(categoryKey);
productsList.DataBind();
}
protected void Page_Load(object sender, EventArgs e) {
this.CachePolicy.Dependency = DependencyFacade.GetProductDependency();
}
由于这一章主要是来理解三层的结构及工厂模式开发,等下一章再来了解一下具体的缓存技术,所以我们先不用看Page_Load,先看看上边的PageChanged方法,productsList是怎么去绑定数据的。
二、业务逻辑层
接口,接口以前以两层开发时感觉没有什么用,也就一直没看了。不过现在必须来恶补回接口的作用了,接口简单理解就是一种约定,使得实现接口的类或结构在形式上保持一致。这里不想再详细讲明接口的作用声明之类的东西自己看书好过我写。
products这里也使用了接口,PetShop将这接口放在了IDAL项目里的IProduct.cs,先来看看代码.
namespace PetShop.IDAL{
public interface IProduct{
IList<ProductInfo> GetProductsByCategory(string category);
IList<ProductInfo> GetProductsBySearch(string[] keywords);
ProductInfo GetProduct(string productId);
}
}
这个IProduct定义了三个方法分别为GetProductsByCategory、GetProductsBySearch、GetProduct,在这里可能先将这个接口理解为在工厂模式下的一个抽象产品,定义这个接口也就方便在结构形式上保持一致。因为接下来的工厂模式都是必须使用这个接口到达到结构的一致。
再来看看产品读取数据是怎么使用这个接口的?首先看回BLL这个项目打开Product.cs,由于前面提到的ProductsControl.ascx这个代码里需要实例化Product,所以直接看Product代码
namespace PetShop.BLL {
public class Product {
private static readonly IProduct dal = PetShop.DALFactory.DataAccess.CreateProduct();
public IList<ProductInfo> GetProductsByCategory(string category) {
if(string.IsNullOrEmpty(category))
return new List<ProductInfo>();
return dal.GetProductsByCategory(category);
}
public IList<ProductInfo> GetProductsBySearch(string text) {
if (string.IsNullOrEmpty(text.Trim()))
return new List<ProductInfo>();
string[] keywords = text.Split();
return dal.GetProductsBySearch(keywords);
}
public ProductInfo GetProduct(string productId) {
if(string.IsNullOrEmpty(productId))
return new ProductInfo();
return dal.GetProduct(productId);
}
}
}
我的理解是看第一句 private static readonly IProduct dal = PetShop.DALFactory.DataAccess.CreateProduct();
定义一个私有的、静态的、只读的类型为IProduct 接口的dal,看到了吧,这里就开始使用这个接口了。然后再看看PetShop.DALFactory.DataAccess.CreateProduct()这个东西
public sealed class DataAccess {
// Look up the DAL implementation we should be using
private static readonly string path = ConfigurationManager.AppSettings["WebDAL"];
private static readonly string orderPath = ConfigurationManager.AppSettings["OrdersDAL"];
private DataAccess() { }
public static PetShop.IDAL.ICategory CreateCategory() {
string className = path + ".Category";
return (PetShop.IDAL.ICategory)Assembly.Load(path).CreateInstance(className);
}
public static PetShop.IDAL.IInventory CreateInventory() {
string className = path + ".Inventory";
return (PetShop.IDAL.IInventory)Assembly.Load(path).CreateInstance(className);
}
public static PetShop.IDAL.IItem CreateItem() {
string className = path + ".Item";
return (PetShop.IDAL.IItem)Assembly.Load(path).CreateInstance(className);
}
public static PetShop.IDAL.IOrder CreateOrder() {
string className = orderPath + ".Order";
return (PetShop.IDAL.IOrder)Assembly.Load(orderPath).CreateInstance(className);
}
public static PetShop.IDAL.IProduct CreateProduct() {
string className = path + ".Product";
return (PetShop.IDAL.IProduct)Assembly.Load(path).CreateInstance(className);
}
}
这里是一个密封的类这个product所用到的就是
public static PetShop.IDAL.IProduct CreateProduct() {
string className = path + ".Product";
return (PetShop.IDAL.IProduct)Assembly.Load(path).CreateInstance(className);
}
这一个,他返回的是一个程序集,他采用反射技术,返回的类型也是那个IProduct这个接口。只需要在配置文件web.config里读取ConfigurationManager.AppSettings["WebDAL"]这一个数值,再看看WebDAL这个值是什么? <add key="WebDAL" value="PetShop.SQLServerDAL"/>
来到这里可以看得出返回的是一个什么样的程序集了,也就是PetShop.SQLServerDAL.Product。这个看起来像是由抽象工厂到具体工厂的实现,可能我对这个工厂模式的设计不太熟,不过感觉应该也是一个抽象工厂到具体工厂的过程,他是经过反射得到的。了解到这里就可以知道了那个bll项目也就业务逻辑层,他不直接操作对象,而仅做一个行为而已。这样做也达到了分离的目的了。
三、数据访问层
接下来看看PetShop.SQLServerDAL.Product
这个开发过程序的人应该都不难看得出来,他是一个直接读取数据库的类。我们取其中的一个方法
public IList<ProductInfo> GetProductsByCategory(string category) {
IList<ProductInfo> productsByCategory = new List<ProductInfo>();
SqlParameter parm = new SqlParameter(PARM_CATEGORY, SqlDbType.VarChar, 10);
parm.Value = category;
//Execute a query to read the products
using (SqlDataReader rdr = SqlHelper.ExecuteReader(SqlHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_SELECT_PRODUCTS_BY_CATEGORY, parm)) {
while (rdr.Read()) {
ProductInfo product = new ProductInfo(rdr.GetString(0), rdr.GetString(1), rdr.GetString(2), rdr.GetString(3), rdr.GetString(4));
productsByCategory.Add(product);
}
}
return productsByCategory;
}
定义一个泛型是productsByCategory 的东西,然后使用SqlHelper.ExecuteReader去读取数据,SqlHelper这也是个好东西,软件提供的东西,给我们使用很方便,最后返回了一个productsByCategory 好了。这里返回的也是之前提过的那个接口,所以感觉接口就是贯穿整个业务及数据访问层。分析完了。
返回 BLL里的Product.cs
我前面提到过 private static readonly IProduct dal = PetShop.DALFactory.DataAccess.CreateProduct(); 这个东西也就很清楚的知道了dal原来就是PetShop.SQLServerDAL.Product了,他们都是同一结构的接口,那么dal.GetProductsByCategory返回后便有值了。
在这里我就可以看到三层结构是如何运作及工厂设计模式是如何开发的了。