昨天,老师给我们展示了简单工厂的设计模式。今天练习了一遍,体会了一下面向接口的编程的强大之处。今天总结一下,加深一下理解。
因为初学C#.net编程,之前做的几个例子都是使用的简单三层架构。而简单三层有个问题,业务操作类与数据操作类是强耦合关系,数据操作类的变动,会直接影响到业务操作类的正常运行,所以为了解决这个问题,需要解耦。怎么解耦,引入接口和工厂类,来将业务操作类与数据操作类的关系变为弱耦合关系。
如左图,图中每条线都代表一个类,图A是一种强耦合关系,一个类的变动就会影响其他类;图B在两个类有关系的地方定义了一个接口,这样类A如何改变都不会影响到类B,这样就达到了解耦的目的,这就是面向接口的编程模式。
下附上两个图来说明下思路:
图A为简单三层,如果数据访问类发生改变(比如:换个数据帮助类文件,就需要修改业务逻辑类里的代码),这样会重复写许多相同的代码。
图B为简单工厂,在业务逻辑类与UI层添加一个接口(I1),在数据访问层与业务逻辑层之间再添加一个接口(I2)。这样不同数据访问层只需要实现I2既可以
思路已经有了,如何用代码实现呢?下面以查询为例简单介绍:
数据访问层代码:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using Test.Model; 6 using System.Data; 7 using System.Data.SqlClient; 8 namespace Test.SqlServerDAL 9 { 10 //Student的数据访问层,实现IStudentDAL接口 11 public class StudentDAL : IDAL.IStudentDAL 12 { 13 //获取所有Student并加入List<Student>中 14 public List<Model.Student> GetAllStudent() 15 { 16 List<Student> list = new List<Student>(); 17 Student stu; 18 string sqlText = "select stuId, stuName, stuAge, stuGender, stuPhone, stuEmail, stuAddress, stuSchool from Student"; 19 using (SqlDataReader sdr = SQLHelper.ExecuteReader(sqlText, CommandType.Text)) 20 { 21 while (sdr.Read()) 22 { 23 stu = new Student(); 24 stu.StuId = sdr.GetInt32(0); 25 stu.StuName = sdr.GetString(1); 26 stu.StuAge = sdr.GetInt32(2); 27 stu.StuGender = sdr.GetString(3); 28 stu.StuPhone = sdr.GetString(4); 29 stu.StuEmail = sdr.GetString(5); 30 stu.StuAddress = sdr.GetString(6); 31 stu.StuSchool = sdr.GetString(7); 32 33 list.Add(stu); 34 } 35 } 36 return list; 37 } 38 } 39 }
子类接口:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using Test.Model; 6 7 namespace IDAL 8 { 9 //子类接口 10 public interface IStudentDAL:IBaseDAL<Student> 11 { 12 List<Student> GetAllStudent();//获取所有学生 13 //增删改方法 14 } 15 }
基类接口,可以封装增删改查方法(只写了查询的方法):
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace IDAL 7 { 8 //基类接口,可以封装增删改查方法,使用了泛型便于获取不同类型的实体,让有相同方法的子类继承,并且给出特定类型。where T:class,new()意思是一个限制,T是一个类,并且可以new(),有个无参的构造函数 9 public interface IBaseDAL<T> where T:class,new() 10 { 11 List<T> GetAllStudent(); 12 } 13 }
工厂类,用于创建数据访问层对象
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using Test.SqlServerDAL; 6 namespace StudentFactoryDAL 7 { 8 public class FactoryDAL 9 { 10 //静态工厂类,用来创建对应的DAL对象 11 public static IDAL.IStudentDAL CreateStudentDAL() 12 { 13 return new StudentDAL(); 14 } 15 } 16 }
业务逻辑层
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using Test.Model; 6 7 namespace Test.BLL 8 { 9 public class StudentBLL:IBLL.IStudentBLL 10 { 11 //通过接口和工厂创建DAL对象 12 IDAL.IStudentDAL dal = StudentFactoryDAL.FactoryDAL.CreateStudentDAL(); 13 //调用dal中的方法,获取所有的学生信息并传给UI层 14 public List<Student> GetAllStudent() 15 { 16 return dal.GetAllStudent(); 17 } 18 } 19 }
同理,可以让业务逻辑层实现接口,并且通过工厂类在表示层后台创建BLL对象,实现业务逻辑层与表现层的解耦。
这样,面向接口的编程就实现了,无论数据访问层怎么修改,只要让它实现上述例子中的子接口就可以了。抽象工厂就是让工厂通过配置文件来动态创建相应的对象,这样更加增加了代码的灵活性。
以上是我自己的理解,如果有错误,还希望大牛们能给指出,谢谢。