工厂模式总结
1.简单工厂——一个工厂创建多类产品(对象)
简单工厂模式(SimpleFactory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例,但它不属于GOF,23种设计模式(参考资料:http://en.wikipedia.org/wiki/Design_Patterns#Patterns_by_Type)。简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数(类的名字,或者类的class对象),对于如何创建对象的逻辑不需要关心。以课程为例,首先创建接口及其具体的实现:
1 package com.gupaoedu.vip.pattern.factory; 2 3 public interface ICourse { 4 //录制课程 5 void record(); 6 }
1 package com.gupaoedu.vip.pattern.factory; 2 3 public class JavaCourse implements ICourse { 4 @Override 5 public void record() { 6 System.out.println("录制Java课程..."); 7 } 8 }
1 package com.gupaoedu.vip.pattern.factory; 2 3 public class PythonCourse implements ICourse { 4 @Override 5 public void record() { 6 System.out.println("录制python课程"); 7 } 8 }
简单工厂:
1 package com.gupaoedu.vip.pattern.factory.simplefactory; 2 import com.gupaoedu.vip.pattern.factory.ICourse; 3 import com.gupaoedu.vip.pattern.factory.JavaCourse; 4 import com.gupaoedu.vip.pattern.factory.PythonCourse; 5 6 /** 7 * 简单工厂,一个工厂可以创建不同的产品(对象) 8 */ 9 public class CourseFactory { 10 public ICourse create(String name) { 11 if ("java".equals(name)) { 12 return new JavaCourse(); 13 } else if("python".equals(name)){ 14 return new PythonCourse(); 15 } else { 16 return null; 17 } 18 } 19 }
客户端调用:
1 package com.gupaoedu.vip.pattern.factory.simplefactory; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 import org.apache.log4j.BasicConfigurator; 5 import org.slf4j.Logger; 6 import org.slf4j.LoggerFactory; 7 8 import java.util.Calendar; 9 10 /** 11 * 简单工厂模式, 12 * 只适用于产品比较少,创建逻辑比较简单的场景 13 */ 14 public class SimpelFactoryTest { 15 16 public static void main(String[] args) { 17 //创建工厂 18 CourseFactory factory = new CourseFactory(); 19 //从工厂获得对象,不必每次都手动new ICourse,缺点,参数传入错误,则获取不到对象 20 ICourse course = factory.create("java"); 21 course.record(); 22 course = factory.create("python"); 23 course.record(); 24 } 25 }
上面的简单工厂存在的问题:如果要新增一个课程,那么工厂类的代码就必须要修改,不符合开闭原则,另外,传入参数错误,将获取不到正确的对象,因此,对工厂类CourseFactory做如下改进:
1 package com.gupaoedu.vip.pattern.factory.simplefactory; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 5 /** 6 * 简单工厂,一个工厂可以创建不同的产品(对象) 7 */ 8 public class CourseFactory { 9 /* public ICourse create(String name) { 10 if ("java".equals(name)) { 11 return new JavaCourse(); 12 } else if("python".equals(name)){ 13 return new PythonCourse(); 14 } else { 15 return null; 16 } 17 }*/ 18 //简单工厂的改进,使用反射机制获取对象 19 public ICourse create(Class clazz) { 20 try { 21 if (null != clazz) { 22 return (ICourse) clazz.newInstance(); 23 } 24 } catch (Exception e) { 25 e.printStackTrace(); 26 } 27 return null; 28 } 29 }
调用代码:
1 package com.gupaoedu.vip.pattern.factory.simplefactory; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 import com.gupaoedu.vip.pattern.factory.JavaCourse; 5 import com.gupaoedu.vip.pattern.factory.PythonCourse; 6 7 /** 8 * 简单工厂模式, 9 * 只适用于产品比较少,创建逻辑比较简单的场景 10 */ 11 public class SimpelFactoryTest { 12 13 public static void main(String[] args) { 14 //创建工厂 15 CourseFactory factory = new CourseFactory(); 16 //从工厂获得对象,不必每次都手动new ICourse,缺点,参数传入错误,则获取不到对象 17 /* ICourse course = factory.create("java"); 18 course.record(); 19 course = factory.create("python"); 20 course.record();*/ 21 22 ICourse javaCourse = factory.create(JavaCourse.class); 23 javaCourse.record(); 24 ICourse pythonCourse = factory.create(PythonCourse.class); 25 pythonCourse.record(); 26 27 } 28 }
2.工厂方法模式(一个工厂只生产一种产品(创建一种对象))
工厂方法模式(FatoryMethodPattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。工厂方法模式主要解决产品扩展的问题,在简单工厂中,随着产品链的丰富,如果每个课程的创建逻辑有区别的话,工厂的职责会变得越来越多,有点像万能工厂,并不便于维护。根据单一职责原则我们将职能继续拆分,专人干专事。 Java课程由Java工厂创建,Python 课程由 Python 工厂创建,对工厂本身也做一个抽象。来看代码,先创建
ICourseFactory接口:(Icourse接口,JavaCourse PythonCourse类不变)
1 package com.gupaoedu.vip.pattern.factory.factorymethod; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 5 /** 6 * 工厂方法模式,一个工厂只能创建一种 产品(返回一种对象) 7 * 这里接口还可以改为抽象类,把一些公共的处理放到抽象类里面 8 */ 9 public interface ICourseFactory { 10 ICourse create(); //这个接口不活,让它的子类干活 11 }
分别创建2个实现类,返回不同的工厂
1 package com.gupaoedu.vip.pattern.factory.factorymethod; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 import com.gupaoedu.vip.pattern.factory.JavaCourse; 5 6 /** 7 * 单一职责,这个工厂只能创建JavaCourse;不同的产品用不同的工厂创建;不同的工厂去负责差异化的创建逻辑 8 */ 9 public class JavaCourseFactory implements ICourseFactory { 10 @Override 11 public ICourse create() { 12 return new JavaCourse(); //这个工厂只能创建JavaCourse,直接new即可 13 } 14 }
1 package com.gupaoedu.vip.pattern.factory.factorymethod; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 import com.gupaoedu.vip.pattern.factory.PythonCourse; 5 6 public class PythonCourseFactory implements ICourseFactory { 7 @Override 8 public ICourse create() { 9 return new PythonCourse(); 10 } 11 }
调用:
1 package com.gupaoedu.vip.pattern.factory.factorymethod; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 5 public class FactoryMethodTest { 6 public static void main(String[] args) { 7 ICourseFactory factory = new PythonCourseFactory(); 8 ICourse course = factory.create(); 9 course.record(); 10 } 11 }
工厂方法适用于以下场景:
(1)创建对象需要大量重复的代码。
(2)客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
(3)一个类通过其子类来指定创建哪个对象。
工厂方法也有缺点:
(1)类的个数容易过多,增加复杂度。
(2)增加了系统的抽象性和理解难度
三,抽象工厂模式
抽象工厂模式(Abastract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。客户端(应用层)不依赖于产品类实例如何被创建、实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。理解抽象工厂之前,先了解两个概念:
产品等级结构和产品族,看下面的图:
同种类称为同等级,同相同等级的一类产品可以由不同的工厂生产,这些不同工厂生产出来的同一类产品,称之为一个产品等级
同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族,下图 所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图。
(图片摘自http://c.biancheng.net/view/1351.html )
现在假设上面的课程进行了升级,现在的业务变更为同一个课程不单纯是一个课程信息,要同时包含录播视频、课堂笔记,甚至还要提供源码才能构成一个完整的课程。在产品等级中增加两个产品IVideo录播
视频和INote课堂笔记。
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public interface ICourse { 4 //录制课程 5 void record(); 6 }
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public interface INote { 4 void edit();//记笔记 5 }
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public interface IVideo { 4 void record(); 5 }
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 5 /** 6 * 要求所有的子工厂都实现 这个工厂 7 * 一个品牌的抽象 8 */ 9 public interface ICourseFactory { 10 ICourse createCourse(); 11 //不仅能创建课程,还能创建笔记和视频 12 INote createNote(); 13 14 IVideo createVideo(); 15 }
实现类:
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public class JavaCourse implements ICourse { 4 @Override 5 public void record() { 6 System.out.println("录制Java课程..."); 7 } 8 }
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public class PythonCourse implements ICourse { 4 @Override 5 public void record() { 6 System.out.println("录制python课程"); 7 } 8 }
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public class JavaNote implements INote { 4 @Override 5 public void edit() { 6 System.out.println("编写java笔记"); 7 } 8 }
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public class PythonNote implements INote { 4 @Override 5 public void edit() { 6 System.out.println("编写python笔记"); 7 } 8 }
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public class JavaVideo implements IVideo { 4 @Override 5 public void record() { 6 System.out.println("录制java视频"); 7 } 8 }
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public class PythonVideo implements IVideo { 4 @Override 5 public void record() { 6 System.out.println("录制python视频"); 7 } 8 }
工厂的实现类:每个工厂都可以生产三种产品
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 import com.gupaoedu.vip.pattern.factory.JavaCourse; 5 6 public class JavaCourseFactory implements ICourseFactory { 7 @Override 8 public ICourse createCourse() { 9 return new JavaCourse(); 10 } 11 12 @Override 13 public INote createNote() { 14 return new JavaNote(); 15 } 16 17 @Override 18 public IVideo createVideo() { 19 return new JavaVideo(); 20 } 21 }
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 import com.gupaoedu.vip.pattern.factory.ICourse; 4 import com.gupaoedu.vip.pattern.factory.PythonCourse; 5 6 public class PythonCourseFactory implements ICourseFactory { 7 @Override 8 public ICourse createCourse() { 9 return new PythonCourse(); 10 } 11 12 @Override 13 public INote createNote() { 14 return new PythonNote(); 15 } 16 17 @Override 18 public IVideo createVideo() { 19 return new PythonVideo(); 20 } 21 }
测试类:
1 package com.gupaoedu.vip.pattern.factory.abstractfactory; 2 3 public class AbstractFactoryTest { 4 public static void main(String[] args) { 5 ICourseFactory factory = new JavaCourseFactory(); 6 //同一个工厂创建多个产品;同一个产品可以被不同的工厂创建 7 factory.createCourse().record(); 8 factory.createNote().edit(); 9 factory.createVideo().record(); 10 11 //python工厂 12 PythonCourseFactory pythonCourseFactory = new PythonCourseFactory(); 13 pythonCourseFactory.createCourse().record(); 14 pythonCourseFactory.createNote().edit(); 15 pythonCourseFactory.createVideo().record(); 16 } 17 }
上面的代码完整地描述了两个产品族Java课程和Python课程,也描述了两个产品等级视频和笔记。抽象工厂非常完美清晰地描述这样一层复杂的关系。但是如果我们再继续扩展产品等级,将源码Source也加入到课程中,那么我们的代码从抽象工厂,到具体工厂要全部调整,很显然不符合开闭原则。因此抽象工厂也是有缺点的:
(1)规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂
的接口。
(2)增加了系统的抽象性和理解难度。
三种工厂模式UML类图对比:
简单工厂模式: 一个工厂创建所有对象(小作坊,什么都生产,工厂和产品一对多)
工厂方法模式:创建工厂接口/抽象类,让子类去创建对象;一套产品分的零部件由不同的工厂生产,每个工厂只生产一种零部件(创建一类对象)(工厂和产品一对一)
抽象工厂模式:不同工厂可以生产相同 的产品(产品族),一个产品可以给不同工厂去生产(产品等级),工厂和产品之间多对多的关系