简单工厂模式

1.需求

一个披萨的项目: 要便于披萨种类的扩展,要便于维护

  1. 披萨的种类很多(比如 GreekPizz、 CheesePizz 等)
  2. 披萨的制作有 prepare,bake, cut, box
  3. 完成披萨店订购功能。

    2.传统解决方式

    02 工厂模式与抽象工厂模式 - 图1
    演示代码:

    1. public class OrderPizza {
    2. public OrderPizza() {
    3. Pizza pizza = null;
    4. String orderType; // 订购披萨的类型
    5. do {
    6. orderType = getType();
    7. if (orderType.equals("greek")) {
    8. pizza = new GreekPizza();
    9. pizza.setName(" 希腊披萨 ");
    10. } else if (orderType.equals("cheese")) {
    11. pizza = new CheesePizza();
    12. pizza.setName(" 奶酪披萨 ");
    13. } else if (orderType.equals("pepper")) {
    14. pizza = new PepperPizza();
    15. pizza.setName("胡椒披萨");
    16. } else {
    17. break;
    18. }
    19. //输出pizza 制作过程
    20. pizza.prepare();
    21. pizza.bake();
    22. pizza.cut();
    23. pizza.box();
    24. } while (true);
    25. }
    26. }

    3.传统方式的优缺点

  4. 优点是比较好理解,简单易操作。

  5. 缺点是违反了设计模式的 ocp 原则,即对扩展开放,对修改关闭。 即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码.
  6. 比如我们这时要新增加一个 Pizza 的种类(Pepper 披萨),我们需要做如下修改.如果我们增加一个 Pizza 类,只要是订购 Pizza 的代码都需要修改

02 工厂模式与抽象工厂模式 - 图2

  1. 改进的思路分析

分析: 修改代码可以接受,但是如果我们在其它的地方也有创建 Pizza 的代码,就意味着,也需要修改,而创建 Pizza的代码,往往有多处。

思路: 把创建 Pizza 对象封装到一个类中,这样我们有新的 Pizza 种类时,只需要修改该类就可,其它有创建到 Pizza对象的代码就不需要修改了 -> 简单工厂模式

4.基本介绍

  1. 简单工厂模式是属于创建型模式,是工厂模式的一种。 简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。 简单工厂模式是工厂模式家族中最简单实用的模式
  2. 简单工厂模式: 定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
  3. 在软件开发中,当我们会用到大量的创建某种、 某类或者某批对象时,就会使用到工厂模式.

    5.使用简单工厂模式

  4. 简单工厂模式的设计方案: 定义一个可以实例化 Pizaa 对象的类,封装创建对象的代码

02 工厂模式与抽象工厂模式 - 图3

  1. 代码示例

    1. //简单工厂类
    2. public class SimpleFactory {
    3. //更加orderType 返回对应的Pizza 对象
    4. public Pizza createPizza(String orderType) {
    5. Pizza pizza = null;
    6. System.out.println("使用简单工厂模式");
    7. if (orderType.equals("greek")) {
    8. pizza = new GreekPizza();
    9. pizza.setName(" 希腊披萨 ");
    10. } else if (orderType.equals("cheese")) {
    11. pizza = new CheesePizza();
    12. pizza.setName(" 奶酪披萨 ");
    13. } else if (orderType.equals("pepper")) {
    14. pizza = new PepperPizza();
    15. pizza.setName("胡椒披萨");
    16. }
    17. return pizza;
    18. }
    19. //简单工厂模式 也叫 静态工厂模式
    20. public static Pizza createPizza2(String orderType) {
    21. Pizza pizza = null;
    22. System.out.println("使用简单工厂模式2");
    23. if (orderType.equals("greek")) {
    24. pizza = new GreekPizza();
    25. pizza.setName(" 希腊披萨 ");
    26. } else if (orderType.equals("cheese")) {
    27. pizza = new CheesePizza();
    28. pizza.setName(" 奶酪披萨 ");
    29. } else if (orderType.equals("pepper")) {
    30. pizza = new PepperPizza();
    31. pizza.setName("胡椒披萨");
    32. }
    33. return pizza;
    34. }
    35. }
    36. public class OrderPizza2 {
    37. public OrderPizza2() {
    38. do {
    39. orderType = getType();
    40. pizza = SimpleFactory.createPizza2(orderType);
    41. // 输出pizza
    42. if (pizza != null) { // 订购成功
    43. pizza.prepare();
    44. pizza.bake();
    45. pizza.cut();
    46. pizza.box();
    47. } else {
    48. System.out.println(" 订购披萨失败 ");
    49. break;
    50. }
    51. } while (true);
    52. }
    53. }

    工厂方法模式

    1.需求

    披萨项目新的需求: 客户在点披萨时,可以点不同口味的披萨,比如北京的奶酪pizza、北京的胡椒pizza 或者是伦敦的奶酪 pizza、 伦敦的胡椒 pizza。
    思路1: 使用简单工厂模式,创建不同的简单工厂类,比如 BJPizzaSimpleFactory,LDPizzaSimpleFactory 等等.从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、 可扩展性并不是特别好
    思路2: 使用工厂方法模式

    2.介绍

  2. 工厂方法模式设计方案: 将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。

  3. 工厂方法模式: 定义了一个创建对象的抽象方法,由子类决定要实例化的类。 工厂方法模式将对象的实例化推迟到子类

    3.应用案例

    02 工厂模式与抽象工厂模式 - 图4
    1. // OrderPizza类
    2. public abstract class OrderPizza {
    3. //定义一个抽象方法,createPizza , 让各个工厂子类自己实现
    4. abstract Pizza createPizza(String orderType);
    5. // 构造器
    6. public OrderPizza() {
    7. Pizza pizza = null;
    8. String orderType; // 订购披萨的类型
    9. do {
    10. orderType = getType();
    11. pizza = createPizza(orderType); //抽象方法,由工厂子类完成
    12. //输出pizza 制作过程
    13. pizza.prepare();
    14. pizza.bake();
    15. pizza.cut();
    16. pizza.box();
    17. } while (true);
    18. }
    19. // 写一个方法,可以获取客户希望订购的披萨种类
    20. private String getType() {
    21. try {
    22. BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
    23. System.out.println("input pizza 种类:");
    24. String str = strin.readLine();
    25. return str;
    26. } catch (IOException e) {
    27. e.printStackTrace();
    28. return "";
    29. }
    30. }
    31. }
    ```java public class BJOrderPizza extends OrderPizza { @Override Pizza createPizza(String orderType) { Pizza pizza = null; if(orderType.equals(“cheese”)) {
    1. pizza = new BJCheesePizza();
    } else if (orderType.equals(“pepper”)) {
    1. pizza = new BJPepperPizza();
    } return pizza; } }

public class LDOrderPizza extends OrderPizza { @Override Pizza createPizza(String orderType) { Pizza pizza = null; if(orderType.equals(“cheese”)) { pizza = new LDCheesePizza(); } else if (orderType.equals(“pepper”)) { pizza = new LDPepperPizza(); } return pizza; } }

  1. ```java
  2. // 演示客户端
  3. public class PizzaStore {
  4. public static void main(String[] args) {
  5. String loc = "bj";
  6. if (loc.equals("bj")) {
  7. //创建北京口味的各种Pizza
  8. new BJOrderPizza();
  9. } else {
  10. //创建伦敦口味的各种Pizza
  11. new LDOrderPizza();
  12. }
  13. }
  14. }

抽象工厂模式

1.介绍

  1. 抽象工厂模式: 定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
  2. 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
  3. 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)
  4. 将工厂抽象成两层AbsFactory(抽象工厂) 具体实现的工厂子类。 程序员可以根据创建对象类型使用对应的工厂子类。 这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
  5. 类图

02 工厂模式与抽象工厂模式 - 图5

2.示例

  1. //一个抽象工厂模式的抽象层(接口)
  2. public interface AbsFactory {
  3. //让下面的工厂子类来 具体实现
  4. public Pizza createPizza(String orderType);
  5. }
  6. //这是工厂子类
  7. public class BJFactory implements AbsFactory {
  8. @Override
  9. public Pizza createPizza(String orderType) {
  10. System.out.println("~使用的是抽象工厂模式~");
  11. Pizza pizza = null;
  12. if(orderType.equals("cheese")) {
  13. pizza = new BJCheesePizza();
  14. } else if (orderType.equals("pepper")){
  15. pizza = new BJPepperPizza();
  16. }
  17. return pizza;
  18. }
  19. }
  20. public class LDFactory implements AbsFactory {
  21. @Override
  22. public Pizza createPizza(String orderType) {
  23. System.out.println("~使用的是抽象工厂模式~");
  24. Pizza pizza = null;
  25. if (orderType.equals("cheese")) {
  26. pizza = new LDCheesePizza();
  27. } else if (orderType.equals("pepper")) {
  28. pizza = new LDPepperPizza();
  29. }
  30. return pizza;
  31. }
  32. }
  1. public class OrderPizza {
  2. AbsFactory factory;
  3. // 构造器
  4. public OrderPizza(AbsFactory factory) {
  5. setFactory(factory);
  6. }
  7. private void setFactory(AbsFactory factory) {
  8. Pizza pizza = null;
  9. String orderType = ""; // 用户输入
  10. this.factory = factory;
  11. do {
  12. orderType = getType();
  13. // factory 可能是北京的工厂子类,也可能是伦敦的工厂子类
  14. pizza = factory.createPizza(orderType);
  15. if (pizza != null) { // 订购ok
  16. pizza.prepare();
  17. pizza.bake();
  18. pizza.cut();
  19. pizza.box();
  20. } else {
  21. System.out.println("订购失败");
  22. break;
  23. }
  24. } while (true);
  25. }
  26. // 写一个方法,可以获取客户希望订购的披萨种类
  27. private String getType() {
  28. try {
  29. BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
  30. System.out.println("input pizza 种类:");
  31. String str = strin.readLine();
  32. return str;
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. return "";
  36. }
  37. }
  38. }

JDK中工厂模式的使用案例

Calendar使用了简单工厂模式

  1. public static void main(String[] args) {
  2. // getInstance 是 Calendar 静态方法
  3. Calendar cal = Calendar.getInstance();
  4. System.out.println("年:" + cal.get(Calendar.YEAR));
  5. System.out.println("月:" + (cal.get(Calendar.MONTH) + 1));
  6. System.out.println("日:" + cal.get(Calendar.DAY_OF_MONTH));
  7. System.out.println("时:" + cal.get(Calendar.HOUR_OF_DAY));
  8. System.out.println("分:" + cal.get(Calendar.MINUTE));
  9. System.out.println("秒:" + cal.get(Calendar.SECOND));
  10. }
  11. public static Calendar getInstance() {
  12. return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
  13. }
  14. private static Calendar createCalendar(TimeZone zone, Locale aLocale){
  15. CalendarProvider provider =
  16. LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
  17. .getCalendarProvider();
  18. if (provider != null) {
  19. try {
  20. return provider.getInstance(zone, aLocale);
  21. } catch (IllegalArgumentException iae) {
  22. // fall back to the default instantiation
  23. }
  24. }
  25. Calendar cal = null;
  26. if (aLocale.hasExtensions()) {
  27. String caltype = aLocale.getUnicodeLocaleType("ca");
  28. if (caltype != null) {
  29. switch (caltype) {
  30. case "buddhist":
  31. cal = new BuddhistCalendar(zone, aLocale);
  32. break;
  33. case "japanese":
  34. cal = new JapaneseImperialCalendar(zone, aLocale);
  35. break;
  36. case "gregory":
  37. cal = new GregorianCalendar(zone, aLocale);
  38. break;
  39. }
  40. }
  41. }
  42. if (cal == null) {
  43. // If no known calendar type is explicitly specified,
  44. // perform the traditional way to create a Calendar:
  45. // create a BuddhistCalendar for th_TH locale,
  46. // a JapaneseImperialCalendar for ja_JP_JP locale, or
  47. // a GregorianCalendar for any other locales.
  48. // NOTE: The language, country and variant strings are interned.
  49. if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
  50. cal = new BuddhistCalendar(zone, aLocale);
  51. } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
  52. && aLocale.getCountry() == "JP") {
  53. cal = new JapaneseImperialCalendar(zone, aLocale);
  54. } else {
  55. cal = new GregorianCalendar(zone, aLocale);
  56. }
  57. }
  58. return cal;
  59. }

工厂模式小结

  1. 工厂模式的意义

将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。 从而提高项目的扩展和维护性。

  1. 三种工厂模式 (简单工厂模式、 工厂方法模式、 抽象工厂模式)
  2. 设计模式的依赖抽象原则

● 创建对象实例时,不要直接 new 类, 而是把这个 new 类的动作放在一个工厂的方法中,并返回。 有的书上说,变量不要直接持有具体类的引用。
● 不要让类继承具体类,而是继承抽象类或者是实现 interface(接口)
● 不要覆盖基类中已经实现的方法。