设计模式 简单工厂+工厂方法+抽象工厂
简单工厂
简单工厂的优缺点:
缺点:①违反了OCP(开放-封闭原则)。(当工厂内增加一个方法创建对象时候,需要在原来的工厂内,添加一个case语句)。修改原来的类,是违反设计原则的。
②增加客户端和工厂类的耦合。
优点:①去除(非降低)客户端和具体产品的耦合。客户端和具体产品中间增加一个工厂类,增加客户端和工厂类的耦合。
②封装工厂类,实现代码多平台的复用性。创建对象的过程被封装成工厂类,可以多平台(控制台+WEB+Winform...手机端)调用这个工厂。
③封装工厂类,创建对象的过程(具体逻辑)包含必要的逻辑,根据客户端的要求,我们可以动态的去创建对象。比如用反射或者new的方式来创建。
“产品”类
public class PersonClass { public string Name { get; set; } public double Height { get; set; } } class WhitePerClass : PersonClass { } class BlackPerClass : PersonClass { } class YellowPerClass : PersonClass { }
“工厂”类:
public static class ClassFactory { public static PersonClass CreateObject(string str) { PersonClass perClass = null; //也可以用反射等逻辑来创建对象。客户端调用时,是管不到我怎么样创建对象的。这是封装的好处之一。 switch (str) { case "white": perClass = new WhitePerClass(); break; case "black": perClass = new BlackPerClass(); break; case "yellow": perClass = new YellowPerClass(); break; } return perClass; } } }
“客户端”:
static void Main(string[] args) { //PersonClass perWhite = new WhitePerClass();//虽然“产品”类PersonClass,采用了面向高层的方法,不用工厂创建对象,还是有一定的耦合。 PersonClass perClass = null; perClass = ClassFactory.CreateObject("white"); perClass.Name = "小白"; perClass.Height = 1.7; Console.WriteLine(perClass.Name + perClass.Height); perClass = ClassFactory.CreateObject("black"); perClass.Name = "小黑"; perClass.Height = 2.1; Console.WriteLine(perClass.Name + perClass.Height); perClass = ClassFactory.CreateObject("yellow"); perClass.Name = "小黄"; perClass.Height = 1.8; Console.WriteLine(perClass.Name + perClass.Height); Console.Read(); }
结果:
再述简单工厂:
产品本身采用了多态。可以new一个产品出来,这样本身降低了客户端和“产品”的耦合,但是未去除耦合。由工厂进一步去除耦合。
缺点:当增加一个产品时,需要在工厂添加一个case语句,修改了原来工厂类。违反了OCP开放封闭原则。
总结简单工厂:
给工厂传一个字符串,返回一个对象。创建逻辑各式各样。
产品树(产品等级)+产品族
都是指的产品。根据品牌和生产厂家分类。
产品树(产品等级):针对产品。指一个产品:品牌不同。
①车(产品):宝马车,奥迪车,奥拓车。
②数据库(产品):MS-SQL,ORACLE,ACCESS,DB2,MongoDB
产品族:针对工厂。一个工厂,产各种产品,各种产品统称一“族”。
①宝马(工厂)生产:宝马自行车,宝马三轮车0.0,宝马的其他产品,衣服,鞋子,宝箱等等。都是一族
②MS-SQL(工厂)生产: user表,department表,role表
工厂方法
特点:只处理一个产品树。可以理解为,只对一张表处理。也是和下面的抽象工厂区别的地方
优点:就是解决简单工厂的缺点(违反了OCP)。和抽象工厂一样,提高程序的扩展性,可以改数据库。增加对应数据库工厂。
缺点:不能增加一个“产品”,只能增加一个工厂,实现了换数据库的功能。但只能处理一个表。若增加一个表就是抽象工厂了。
类图:
个人总结:我们平时用到了工厂模式,一般属于简单工厂或者抽象工厂,因为可以对多个表处理。
抽象工厂
优点:去除了简单工厂的违反OCP原则,通过添加子类,而不是改变原来类。来增加”产品“。
缺点:每增加一个产品:需要添加一个产品接口+sql产品+oracle产品,还要增加工厂接口+sql工厂+oracle工厂的一个方法。
“产品“类
用户:
interface IUserDal { void CRUD(); } class SqlUserDal : IUserDal { public void CRUD() { Console.WriteLine("sql数据库User的CRUD"); } } class OracleUserDal : IUserDal { public void CRUD() { Console.WriteLine("Oracle数据库User的CRUD"); } }
部门:
interface IDepartmentDal { void CRUD(); } class SqlDepartmentDal : IDepartmentDal { public void CRUD() { Console.WriteLine("sql数据库Department的CRUD"); } } class OracleDepartmentDal : IDepartmentDal { public void CRUD() { Console.WriteLine("Oracle数据库Department的CRUD"); } }
”工厂“类
interface IFactory { IUserDal CreateUserDal(); IDepartmentDal CreateDepartmentDal(); } class SqlFactory : IFactory { public IUserDal CreateUserDal() { return new SqlUserDal(); } public IDepartmentDal CreateDepartmentDal() { return new SqlDepartmentDal(); } } class OracleFactory : IFactory { public IUserDal CreateUserDal() { return new OracleUserDal(); } public IDepartmentDal CreateDepartmentDal() { return new OracleDepartmentDal(); } }
客户端:
static void Main(string[] args) { //创建Sql对应dal SqlFactory sqlFactory=new SqlFactory(); IUserDal sqlUserDal = sqlFactory.CreateUserDal(); sqlUserDal.CRUD(); IDepartmentDal sqlDeparmentDal = sqlFactory.CreateDepartmentDal(); sqlDeparmentDal.CRUD(); //换数据库了,需要创建Oracle对应Dal OracleFactory oracleFactory = new OracleFactory(); IUserDal oracleUserDal = oracleFactory.CreateUserDal(); oracleUserDal.CRUD(); IDepartmentDal oracleDeparmentDal = oracleFactory.CreateDepartmentDal(); oracleDeparmentDal.CRUD(); Console.Read(); }
结果:
总结:
①理解产品族和产品树(产品等级),方便记忆类图。
②知道工厂方法和抽象工厂的区别
③工厂方法和抽象工厂改善了简单工厂的缺点(违反ocp),带来的缺点是什么。
为了改变抽象工厂增加一个”产品“,带来的繁琐代码,你想到怎么改进了吗?