设计模式——工厂模式
更多内容,前往 IT-BLOG
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单使用的模式。简单工厂模式定义了一个创建对象的类,由这个类来封装实例化对象的行为。在软件开发中,当我们会用到大量的创建某种、某类或者某批量对象时,就会使用到工厂模式。
一、简单工厂模式案例
需求:用户可以通过一个披萨工厂类来获取自己想要的披萨。
工厂模式设计方案:首先将披萨项目的实例抽象成抽象方法,在不同的口味子类中具体实现。同时定义一个披萨的工厂类 (SimplePizzaFactory)来获取想要的披萨对象。它向工厂类中传递信息(GREEK 等),以便获取它所需要的对象类型。
类图:通过类图,查看构建的思路:如果有新的品种只需修改提供方,应用方无需修改。
【1】定义一个接口 Pizza
1 package com.yintong.principle.singleresponsibility; 2 //将Pizza 做成一个接口 3 public interface Pizza { 4 //准备原材料, 不同的披萨不一样,因此,我们做成抽象方法 5 public void prepare(); 6 }
【2】定义披萨的种类,实现 Pizza 接口,如下定义了 GREEK、CHEESE 两种披萨。如果后续有新的种类可以实现 Pizza 接口,继续添加新的品种。
1 //希腊披萨 2 public class GreekPizza implements Pizza{ 3 4 @Override 5 public void prepare() { 6 System.out.println(" 给希腊披萨 准备原材料 "); 7 } 8 } 9 //奶酪披萨 10 public class CheesePizza implements Pizza{ 11 12 @Override 13 public void prepare() { 14 System.out.println(" 给制作奶酪披萨 准备原材料 "); 15 } 16 }
【3】 创建一个简单的工厂类对象 SimpleFactory
1 public class SimpleFactory { 2 //传入 orderType(种类) 返回对应的 Pizza 对象 3 public Pizza createPizza(String orderType) { 4 Pizza pizza = null; 5 //使用简单工厂模式 6 if (orderType.equals("greek")) { 7 //希腊披萨 8 pizza = new GreekPizza(); 9 } else if (orderType.equals("cheese")) { 10 //奶酪披萨 11 pizza = new CheesePizza(); 12 } 13 return pizza; 14 } 15 }
【4】在应用代码 OrderPizza 中调用工厂类,获取用户需要的披萨对象。
1 public class OrderPizza { 2 //定义用户要获取的披萨类型 3 private static final String pizza = "greek"; 4 public static void main(String[] args) { 5 //通过工厂获取希腊披萨 6 SimpleFactory simpleFactory = new SimpleFactory(); 7 //greekPizza 就是我们需要获取的目标披萨 8 Pizza greekPizza = simpleFactory.createPizza(pizza); 9 //调用目标披萨的方法 10 greekPizza.prepare(); 11 } 12 }
二、工厂模式的优缺点
优点:1)、一个调用者想创建一个对象,只要知道其名称就可以了。
2)、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3)、屏蔽产品的具体实现,调用者只关心产品接口。
缺点:每增加一个产品时,都需要增加一个具体实现类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别只需要通过 new 就可以完成创建的对象,无需工厂模式。如果使用工厂模式就需要使用工厂类,会增加系统的复杂度。
三、抽象工厂方法模式
需求:在上述的基础上,添加了地区。例如:用户可以点北京的奶酪披萨,北京的胡椒披萨,或者伦敦的奶酪披萨,伦敦的胡椒披萨。
工厂方法设计模式:1)、定义一个 interface(工厂的接口) 用于创建相关或者依赖关系的对象簇,而无需指明具体对象类。
2)、从设计层面来看,抽象工厂模式就是简单工厂模式的改进(或者称为进一步抽象)。
3)、将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更有利于代码的维护和扩展。
类图:将简单工厂模式中的工厂类抽象成了一个接口,易于后期扩展。
【1】定义工厂类的接口(AbsFactory)
1 //一个抽象工厂模式的抽象层(接口) 2 public interface AbsFactory { 3 //让下面的工厂子类来 具体实现 4 public Pizza createPizza(String orderType); 5 }
【2】让北京和伦敦的工厂类实现此接口(与简单工厂类的区别就是实现了 AbsFactory 接口,伦敦略)
1 public class BJFactory implements AbsFactory{ 2 //更加orderType 返回对应的Pizza 对象 3 public Pizza createPizza(String orderType) { 4 Pizza pizza = null; 5 //使用简单工厂模式 6 if (orderType.equals("greek")) { 7 //希腊披萨 8 pizza = new GreekPizza(); 9 } else if (orderType.equals("cheese")) { 10 //奶酪披萨 11 pizza = new CheesePizza(); 12 } 13 return pizza; 14 } 15 }
【3】在 Order 订单应用中,与接口 AbsFactory 进行组合。
1 public class OrderPizza { 2 AbsFactory factory; 3 //定义构造器 4 public OrderPizza(AbsFactory factory){ 5 this.factory = factory; 6 } 7 //定义用户要获取的披萨类型,可以定义一个变量从客户端传入 8 private static final String pizza = "greek"; 9 public void main(String[] args) { 10 //greekPizza 就是我们需要获取的目标披萨 11 Pizza greekPizza = factory.createPizza(pizza); 12 //调用目标披萨的方法 13 greekPizza.prepare(); 14 } 15 }
四、工厂模式在 JDK-Calendar 类中的应用
五、工厂模式小结
1)、工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
2)、设计模式依赖抽象原则:创建对象实例时,不要直接 new 类,而是把这个 new 类的动作放在一个工厂的方法中,并返回。不要让类继承具体类,而是继承抽象类或者实现 interface(接口)。不要覆盖基类中已经实现的方法。