设计模式——工厂模式

更多内容,前往 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 //1、调用 Calendar 对象
 2 Calendar instance = Calendar.getInstance();
 3 //2、进入 Calendar.getInstance() 方法
 4 public static Calendar getInstance()
 5 {
 6     return createCalendar(TimeZone.getDefault(),Locale.getDefault(Locale.Category.FORMAT));
 7 }
 8 //3、进入 createCalendar 方法
 9 private static Calendar createCalendar(TimeZone zone,Locale aLocale){
10     CalendarProvider provider =
11         LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
12                              .getCalendarProvider();
13     if (provider != null) {
14         try {
15             return provider.getInstance(zone, aLocale);
16         } catch (IllegalArgumentException iae) {
17             // fall back to the default instantiation
18         }
19     }
20 
21     Calendar cal = null;
22     
23     if (aLocale.hasExtensions()) {
24         String caltype = aLocale.getUnicodeLocaleType("ca");
25         if (caltype != null) {
26             //该出就是我们要重点查看的部分,根据用户需求,创建Calendar 对象
27             switch (caltype) {
28             case "buddhist":
29             cal = new BuddhistCalendar(zone, aLocale);
30                 break;
31             case "japanese":
32                 cal = new JapaneseImperialCalendar(zone, aLocale);
33                 break;
34             case "gregory":
35                 cal = new GregorianCalendar(zone, aLocale);
36                 break;
37             }
38         }
39     }
40     return cal;
41 }

五、工厂模式小结


1)、工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
2)、设计模式依赖抽象原则:创建对象实例时,不要直接 new 类,而是把这个 new 类的动作放在一个工厂的方法中,并返回。不要让类继承具体类,而是继承抽象类或者实现 interface(接口)。不要覆盖基类中已经实现的方法。

posted @ 2020-11-19 14:21  Java程序员进阶  阅读(147)  评论(0编辑  收藏  举报