我的工程实践项目是Java Web相关,使用了Spring框架。
在Java面向过程的概念中:一切皆对象!但是大量对象的创建、调用和删除在大型项目中是一件很复杂的事情,而Spring框架大大简化了这一过程。众所周知,Spring框架的核心就是IOC,把对象的创建、管理和删除全部交给IOC容器管理。这就免不了工厂模式的使用。
那么什么是工厂模式?
举一个简单的例子。假如我们制作一款绘图工具。可以绘制圆形,正方形,三角形等各种图形,每个图形都有一个draw()方法用于绘图。如果我们需要创建一个图形,对于Java面向对象来说,我们并不需要亲自去绘制,只需要下达相关的指令,由能够解析指令的工具自动帮我们完成就好。在工厂模式中,工厂类就是这个能解析指令自动完成的重要工具,我们把所有的逻辑业务都交给工厂去办。
为什么要用工厂模式?
对于调用者来说,工厂模式隐藏了复杂的逻辑处理过程,调用者只关心执行结果,而由工厂类保证生产出符合规范的产品。有以下三个好处:
(1) 解耦 :把对象的创建和使用的过程分开。
(2) 降低代码重复: 如果创建某个对象的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。
(3) 降低维护成本 :由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建对象B的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。
工厂模式的具体实现?
工厂模式分为三种:
1.简单工厂模式,只适合简单的情况。
2.工厂方法模式,把简单的工厂模式抽象化了,适合更加复杂的程序设计。
3.抽象工厂模式,工厂类中只写一个抽象方法,让其他类继承并重写该方法。
介绍一下简单工厂模式。我们必须制作一个工厂(Factory)角色 :它是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
假如我们制作一款绘图工具。可以绘制圆形,正方形,三角形等各种图形,每个图形都有一个draw()方法用于绘图。我们可以定义一个工厂类ShapeFactory,它会根据指令创建不同形状的形状类并返回,而不需要用户亲自去创建。
public class ShapeFactory { // 使用 getShape 方法获取形状类型的对象 public static Shape getShape(String shapeType) { if (shapeType == null) { return null; } if (shapeType.equalsIgnoreCase("CIRCLE")) { return new Circle(); } else if (shapeType.equalsIgnoreCase("RECTANGLE")) { return new Rectangle(); } else if (shapeType.equalsIgnoreCase("SQUARE")) { return new Square(); } return null; } }
这样一来,如果我们想创建图形类,就可以直接通过工厂类ShapFactory的getShape方法得到新建的 circle/rectangle/square 对象并使用。
public class Test { public static void main(String[] args) { // 获取 Circle 的对象,并调用它的 draw 方法 Shape circle = ShapeFactory.getShape("CIRCLE"); circle.draw(); // 获取 Rectangle 的对象,并调用它的 draw 方法 Shape rectangle = ShapeFactory.getShape("RECTANGLE"); rectangle.draw(); // 获取 Square 的对象,并调用它的 draw 方法 Shape square = ShapeFactory.getShape("SQUARE"); square.draw(); } }
简单工厂模式代码简单,逻辑清晰,但通常简单带来的弊病就是后期维护难。假如我们有一个新的成员要加入,那么就需要修改工厂类,这就完全违背了ocp(对扩展开放,对修改封闭)原则。如果想改善这一点,一方面可以使用反射机制(Spring也用到了这个方法,但因为篇幅问题不再展开),另一方面,可以该用工厂方法模式,这也是在工厂模式家族中是用的最多模式。
工厂方法模式是简单工厂的仅一步深化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说 每个对象都有一个与之对应的工厂 。
//接口 public interface Factory { public Shape getShape(); } //圆形工厂类 public class CircleFactory implements Factory { @Override public Shape getShape() { // TODO Auto-generated method stub return new Circle(); } } //三角形工厂类 public class RectangleFactory implements Factory{ @Override public Shape getShape() { // TODO Auto-generated method stub return new Rectangle(); } } //长方形工厂类 public class SquareFactory implements Factory{ @Override public Shape getShape() { // TODO Auto-generated method stub return new Square(); } }
这样当我们想创建一个圆形对象时,只需要调用相应的工厂类来实现。
public class Test { public static void main(String[] args) { Factory circlefactory = new CircleFactory(); Shape circle = circlefactory.getShape(); circle.draw(); } }
那么什么是抽象工厂模式?
抽象工厂模式是工厂方法的仅一步深化,在这个模式中的工厂类不单单可以创建一种产品,而是可以创建一组产品。当我们需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况(同属于同一个产品族的产品)且系统结构稳定,不会频繁的增加对象时(因为一旦增加就需要修改原有代码,不符合开闭原则),我们可以采用抽象工厂方法。
比方说,我们绘制圆形时,往往还要返回一个点的集体类来确定圆心。我们可以在同一个工厂内用不同的方法来实现。
public class circleFactory implements Factory{ //确定圆心 @Override public Dot getCentor() { return new Dot(); } //绘图 @Override public Circle getShape() { return new circle(); } }
这样我们就可以在一个工厂类里创建不同的对象组合。、
public class Test { public static void main(String[] args) { Factory factory = new CircleFactory(); Dot dot = factory.getCentor(); dot.find(); Circle circle = factory.getShape(); circle.draw(); } }
Spring中工厂类的使用
在Spring框架中,定义了两个工厂类 BeanFactory 和 ApplicationContext ,来为容器自动创建bean(对象实体)服务,即实现getBean方法。两者有以下两个区别:
ApplicationContext 是 BeanFactory 的子接口,提供了比父接口更多的功能。
在生成 bean 实例的时候,生成的时机是不一样的。BeanFactory 在工厂实例化后,在调用 getBean 时创建实例。ApplicationContext 在加载配置文件的时候,将配置文件中所有单例模式生成的类全部实例化。
在框架使用过程中,我们就可以通过工厂类读取XML配置文件,实现对bean的实例化。
@Test public void demo() { //创建工厂类 BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("e:\\applicationContext.xml")); //通过工厂获得类 UserService userService = (UserService) beanFactory.getBean("userService"); //通过对象执行方法 userService.sayHello(); }
在Spring框架使用Bean管理对象,大大降低了项目的耦合性。各个对象之间不再有复杂的耦合关系,只和IOC容器类进行耦合,互相不再干扰。为项目开发的模块化、封装做出了重要贡献。
在以前刚刚学习Spring框架的时候,也自己尝试实现过一些简单的IOC容器,来实现工厂模式。因为年代久远,只找到了截图。把代码贴在下方,有助于理解其中的原理:
原文:https://www.cnblogs.com/mrjoker97/p/12002011.html