设计模式篇(Java):工厂模式

上一篇:设计模式篇(Java):单例模式

五、工厂模式

需求示例

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

  • 披萨的种类很多(比如 GreekPizz、CheesePizz 等)

  • 披萨的制作过程有 prepare,bake, cut, box。

  • 完成披萨店订购功能。

使用传统的方法(不使用设计模式)

披萨类及其子类:

/**
 * @author cVzhanshi
 * @create 2023-04-17 16:45
 */
@Slf4j
public abstract class Pizza {
    
    
    public abstract void prepare();

    public void bake() {
    
    
        log.info("bake()");
    }

    public void cut() {
    
    
        log.info("cut()");
    }

    public void box() {
    
    
        log.info("box()");
    }
}


@Slf4j
public class GreekPizza extends Pizza {
    
    
    @Override
    public void prepare() {
    
    
        log.info("prepare() ---> GreekPizza");
    }
}
...

订单类

@Slf4j
public class OrderPizza {
    
    
    public void generateOrder(String type) {
    
    
        Pizza pizza;
        if (type.equals("greek")) {
    
    
            pizza = new GreekPizza();
        } else if (type.equals("cheese")) {
    
    
            pizza = new CheesePizza();
        } else {
    
    
            log.info("选择错误");
            return;
        }
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
    }
}

分析:

  • 代码比较好理解
  • 违反了开闭原则,即对扩展开放,对修改关闭。如果新增一种披萨,需要新增一个类,然后在订单业务中添加if分支。而订单业务也许会部署在多个商店中,订单业务相对于说是使用者,使用者应该对应的关闭,即不允许修改,要修改只能在扩展修改。

5.1 简单工厂模式

  • 简单工厂模式(静态工厂模式)是属于创建型模式,是工厂模式的一种。简单工厂模式是由一 个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族 中最简单实用的模式。

  • 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)

  • 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会 使用到工厂模式

简单工厂模式实现上述例子

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

工厂类:

/**
 * @author cVzhanshi
 * @create 2023-04-17 17:14
 */
public class SimplePizzaFactory {
    
    

    public static Pizza createPizza(String type) {
    
    
        Pizza pizza = null;
        if (type.equals("greek")) {
    
    
            pizza = new GreekPizza();
        } else if (type.equals("cheese")) {
    
    
            pizza = new CheesePizza();
        }
        return pizza;
    }

}

订单类修改:

@Slf4j
public class OrderPizza {
    
    
    public void generateOrder(String type) {
    
    
        Pizza pizza = SimplePizzaFactory.createPizza(type);
        if (pizza != null) {
    
    
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        }
    }
}

5.2 工厂方法模式

针对上诉案例增加新需求:

披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪pizza、 北京的胡椒pizza 或者是伦敦的奶酪pizza、伦敦的胡椒pizza。

对于新需求,使用简单工厂模式也能实现,但是考虑到项目的 规模,以及软件的可维护性、可扩展性并不是特别好。

思路:使用工厂方法模式

工厂方法模式介绍

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

代码示例:

  • 首先抽象创建披萨类创造步骤为方法

    /**
     * @author cVzhanshi
     * @create 2023-04-17 16:48
     */
    @Slf4j
    public abstract class OrderPizza {
          
          
        public abstract Pizza createPizza(String type);
        public void generateOrder(String type) {
          
          
            Pizza pizza = createPizza(type);
            if (pizza != null) {
          
          
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }
        }
    }
    
  • 根据不同口味创建不同的实现类

    @Slf4j
    public class BJOrderPizza extends OrderPizza{
          
          
        @Override
        public Pizza createPizza(String type) {
          
          
            Pizza pizza = null;
            if (type.equals("greek")) {
          
          
                pizza = new BJGreekPizza();
            } else if (type.equals("cheese")) {
          
          
                pizza = new BJCheesePizza();
            }
            return pizza;
        }
    }
    
    @Slf4j
    public class LDOrderPizza extends OrderPizza{
          
          
        @Override
        public Pizza createPizza(String type) {
          
          
            Pizza pizza = null;
            if (type.equals("greek")) {
          
          
                pizza = new LDGreekPizza();
            } else if (type.equals("cheese")) {
          
          
                pizza = new LDCheesePizza();
            }
            return pizza;
        }
    }
    

5.3 抽象工厂模式

  • 抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类

  • 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合

  • 将工厂抽象成两层,AbsFactory(抽象工厂) 和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇, 更利于代码的维护和扩展。

代码示例:

  • 一个抽象工厂模式的抽象层(接口)

    /**
     * @author cVzhanshi
     * @create 2023-04-18 14:53
     */
    public interface AbsFactory {
          
          
        Pizza createPizza(String orderType);
    }
    
  • 抽象子类

    /**
     * @author cVzhanshi
     * @create 2023-04-18 14:55
     */
    public class LDFactory implements AbsFactory {
          
          
        @Override
        public Pizza createPizza(String orderType) {
          
          
            Pizza pizza = new BJCheesePizza();
            if (orderType.equals("cheese")) {
          
          
                pizza = new LDCheesePizza();
            } else if (orderType.equals("greek")) {
          
          
                pizza = new LDGreekPizza();
            }
            return pizza;
        }
    }
    
    
    /**
     * @author cVzhanshi
     * @create 2023-04-18 14:55
     */
    public class BJFactory  implements AbsFactory {
          
          
        @Override
        public Pizza createPizza(String orderType) {
          
          
            Pizza pizza = new BJCheesePizza();
            if (orderType.equals("cheese")) {
          
          
                pizza = new BJCheesePizza();
            } else if (orderType.equals("greek")) {
          
          
                pizza = new BJGreekPizza();
            }
            return pizza;
        }
    }
    
  • 订单类,可以忽视底层使用的哪个工厂类

    /**
     * @author cVzhanshi
     * @create 2023-04-18 15:06
     */
    public class OrderPizza {
        private AbsFactory absFactory;
    
        public OrderPizza(AbsFactory absFactory, String ordertype) {
            this.absFactory = absFactory;
            Pizza pizza;
            pizza = absFactory.createPizza(ordertype);
            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }
        }
    }
    

5.4 jdk代码中的体现

Calendar.getInstance();就是很好的一个体现,如代码:

public static Calendar getInstance(Locale aLocale)
{
    
    
    return createCalendar(TimeZone.getDefault(), aLocale);
}



public static Calendar getInstance(TimeZone zone,
                                   Locale aLocale)
{
    
    
    return createCalendar(zone, aLocale);
}

private static Calendar createCalendar(TimeZone zone,
                                       Locale aLocale)
{
    
    
    CalendarProvider provider =
        LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
        .getCalendarProvider();
    if (provider != null) {
    
    
        try {
    
    
            return provider.getInstance(zone, aLocale);
        } catch (IllegalArgumentException iae) {
    
    
            // fall back to the default instantiation
        }
    }

    Calendar cal = null;

    if (aLocale.hasExtensions()) {
    
    
        String caltype = aLocale.getUnicodeLocaleType("ca");
        if (caltype != null) {
    
    
            switch (caltype) {
    
    
                case "buddhist":
                    cal = new BuddhistCalendar(zone, aLocale);
                    break;
                case "japanese":
                    cal = new JapaneseImperialCalendar(zone, aLocale);
                    break;
                case "gregory":
                    cal = new GregorianCalendar(zone, aLocale);
                    break;
            }
        }
    }
    if (cal == null) {
    
    
        if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
    
    
            cal = new BuddhistCalendar(zone, aLocale);
        } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                   && aLocale.getCountry() == "JP") {
    
    
            cal = new JapaneseImperialCalendar(zone, aLocale);
        } else {
    
    
            cal = new GregorianCalendar(zone, aLocale);
        }
    }
    return cal;
}

5.5 小结

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

猜你喜欢

转载自blog.csdn.net/qq_45408390/article/details/131405046