设计模式学习第三节 工厂模式

案例分析

    先梳理一个需要:披萨->要求便于披萨种类的扩展与维护
    1、披萨的种类有很多(CheesePizza、BeefPizza…)。2、Pizza的制作有:prepare、bake、cut、box
    先梳理设计类图在这里插入图片描述
    代码实现

package com.example.pattern.factory.pizza;

/**
 * @author zjt
 * @date 2020-12-02
 */
public abstract class Pizza {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 先忽略其它共有属性

    public abstract void prepare();

    public void bake() {
        System.out.println(this.name + " baking");
    }

    public void cut() {
        System.out.println(this.name + " cutting");
    }

    public void box() {
        System.out.println(this.name + " boxing");
    }

}

package com.example.pattern.factory.pizza;

/**
 * @author zjt
 * @date 2020-12-02
 */
public class BeefPizza extends Pizza {

    public BeefPizza(String name) {
        super.setName(name);
    }

    @Override
    public void prepare() {
        System.out.println(super.getName() + " 准备原材料");
    }
}
package com.example.pattern.factory.pizza;

/**
 * @author zjt
 * @date 2020-12-02
 */
public class CheesePizza extends Pizza {

    public CheesePizza(String name) {
        super.setName(name);
    }

    @Override
    public void prepare() {
        System.out.println(super.getName() + " 准备原材料");
    }

}

public class OrderPizza {
    public static void main(String[] args) {
        OrderPizza order = new OrderPizza();
        order.testTradition();
        //order.testSimpleFactory();
	    //order.testFactoryMethod();
	    //order.testFactoryMethod1()
    }
public void testTradition() { // type B 和 C
        Scanner scan = new Scanner(System.in);
        do {
            System.out.println("请输入想要购买的 Pizza :");
            String type = scan.next();
            Pizza pizza = this.createByType(type, str -> {
                switch (str) {
                    case "B":
                        return new BeefPizza("牛肉pizza");
                    case "C":
                        return new CheesePizza("芝士pizza");
                    default:
                        return null;
                }
            });
            if (null == pizza) {
                System.out.println(" Pizza 种类错误 ");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }

    public Pizza createByType(String type, Function<String, Pizza> fin) {
        return fin.apply(type);
    }

}

    优缺点分析:这种方式的优点是写法简单;缺点是违反了设计模式的OCP原则,即对扩展开开放、对修改关闭。我们希望给类增加新的功能的时候,尽量不修改或尽量少修改代码。比如我们给Pizza 新增一个种类,我们不仅需要新增类,还要在使用方 order中添加相关的方法 case XXX …
    改进思路
    分析:修改代码可以接受,但是如果我们在其它地方也有创建Pizza的代码,也是需要修改的,如果有遗漏,会带来程序错误,可维护性差
    思路: 把创建Pizza对象封装到一个类中,这样我们有新的种类时,只需要修改该类即可,其它创建Pizza对象的代码就不需要修改了

简单工厂模式

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

package com.example.pattern.factory.pizza;

/**
 * @author zjt
 * @date 2020-12-02
 */
public  class SimplePizzaFactory {

    // 结合单例模式使用 不希望SimplePizzaFactory这个工厂每次使用的时候都去 new SimplePizzaFactory 对象
    public static volatile SimplePizzaFactory simplePizzaFactory;

    private SimplePizzaFactory() {
    }

    public static SimplePizzaFactory getInstance() {
        if (null == simplePizzaFactory) {
            synchronized (SimplePizzaFactory.class) {
                if (null == simplePizzaFactory) {
                    simplePizzaFactory = new SimplePizzaFactory();
                }
            }
        }
        return simplePizzaFactory;
    }

    public Pizza createPizza(String type) {
        switch (type) {
            case "B":
                return new BeefPizza("牛肉披萨");
            case "C":
                return new CheesePizza("芝士披萨");
            case "D":
                return new DurianPizza("榴莲披萨");
            default:
                return null;
        }

    }
}
public class DurianPizza extends Pizza {

    public DurianPizza(String name) {
        super.setName(name);
    }

    @Override
    public void prepare() {
        System.out.println(super.getName() + " 准备原材料");
    }
}

    OrderPizza类中新增方法

public void testSimpleFactory() {
        Scanner scan = new Scanner(System.in);
        SimplePizzaFactory instance = SimplePizzaFactory.getInstance();
        Pizza pizza;
        do {
            System.out.println("请输入想要购买的 Pizza :");
            String type = scan.next();
            pizza = instance.createPizza(type);
            if (null == pizza) {
                System.out.println(" Pizza 种类错误 ");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }

工厂方法模式

    增加了一个新的需求 :客户点披萨的时候可以选择尺寸。比如7存的、10寸的披萨 希望不同的尺寸的pizza由不同的工厂制作出来
    思路1:直接解决 创建多个简单工厂类,比如 SimpleSize7PizzaFactory,但是考虑到代码的扩展性和可维护性,我们可以使用工厂方法模式
    工厂方法模式设计方案:将具体实例化的功能作为抽象方法,在不同尺寸的子类中具体实现
    工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类

public abstract class AbstractPizzaFactory {

   // 工厂方法模式
   // 增加了一个新的需求 :客户点披萨的时候可以选择尺寸。比如7存的、10寸的披萨 希望不同的尺寸的pizza由不同的工厂制作出来
   // 思路1:直接解决 创建多个简单工厂类,比如 SimpleSize7PizzaFactory,
   // 但是考虑到代码的扩展性和可维护性,我们可以使用工厂方法模式
   // 工厂方法模式设计方案:将具体实例化的功能作为抽象方法,在不同尺寸的子类中具体实现
   // 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类

   public abstract Pizza createPizzaBySize(String type);

}
public class Size7PizzaFactory extends AbstractPizzaFactory {

    private Size7PizzaFactory() {
    }

    public static Size7PizzaFactory getInstance() {
        return Size7PizzaFactoryInstance.FACTORY;
    }

    @Override
    public Pizza createPizzaBySize(String type) {
        switch (type) {
            case "B":
                return new BeefPizza("7寸的牛肉披萨");
            case "C":
                return new CheesePizza("7寸的芝士披萨");
            case "D":
                return new DurianPizza("7寸的榴莲披萨");
            default:
                return null;
        }
    }

    private static class Size7PizzaFactoryInstance {
        private static final Size7PizzaFactory FACTORY = new Size7PizzaFactory();
    }

}
public class Size10PizzaFactory extends AbstractPizzaFactory {

    private Size10PizzaFactory() {
    }

    public static Size10PizzaFactory getInstance() {
        return Size10PizzaFactory.Size10PizzaFactoryInstance.FACTORY;
    }

    @Override
    public Pizza createPizzaBySize(String type) {
        switch (type) {
            case "B":
                return new BeefPizza("10寸的牛肉披萨");
            case "C":
                return new CheesePizza("10寸的芝士披萨");
            case "D":
                return new DurianPizza("10寸的榴莲披萨");
            default:
                return null;
        }
    }

    private static class Size10PizzaFactoryInstance {
        private static final Size10PizzaFactory FACTORY = new Size10PizzaFactory();
    }

}

抽象工厂模式

    基本介绍
    抽象工厂模式:定义一个interface用于创建相关或者有依赖关系的对象簇,无需指明具体的类。
    抽象工厂模式可以将简单工厂和工厂方法模式进行整合。从设计层面上看,抽象工厂模式就是对简单工厂和工厂方法模式的进一步整改(或者说进一步抽象)。
    将工厂抽象为两层,AbstractFactory(抽象工厂)和具体实现的工厂子类。我们可以根据创建对象类型使用对应的工厂子类。这样将单个简单工厂变成了工厂簇,更利于代码的维护和扩展。
在这里插入图片描述

public interface AbstractInterfaceFactory {
    Pizza createByFactory(String type);
}
public class Size7Factory implements AbstractInterfaceFactory {

    @Override
    public Pizza createByFactory(String type) {
        System.out.println("抽象工厂类");
        switch (type) {
            case "B":
                return new BeefPizza("7寸的牛肉披萨");
            case "C":
                return new CheesePizza("7寸的芝士披萨");
            case "D":
                return new DurianPizza("7寸的榴莲披萨");
            default:
                return null;
        }
    }

}
public class Size10Factory implements AbstractInterfaceFactory{

    @Override
    public Pizza createByFactory(String type) {
        System.out.println("抽象工厂类");
        switch (type) {
            case "B":
                return new BeefPizza("10寸的牛肉披萨");
            case "C":
                return new CheesePizza("10寸的芝士披萨");
            case "D":
                return new DurianPizza("10寸的榴莲披萨");
            default:
                return null;
        }
    }
}

     OrderPizza 新增测试方法

    public void testFactoryMethod1() {
        Scanner scan = new Scanner(System.in);
        do {
            System.out.println("请输入想要购买的 Pizza 尺寸 :");
            String size = scan.next();
            System.out.println("请输入想要购买的 Pizza 种类:");
            String type = scan.next();
            AbstractInterfaceFactory factory;
            if ("7".equalsIgnoreCase(size)){
                 factory = new Size7Factory();
            }else {
                factory = new Size10Factory();
            }
            Pizza pizza = factory.createByFactory(type);
            if (null == pizza) {
                System.out.println(" Pizza 种类错误 ");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }

JDK使用工厂模式的源码分析

    JDK中的Calendar类使用到了简单工厂模式,源码追踪如下。

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; // 捕捉到了异常,往下走准备构造Calendar实例

        if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) { //  根据传入的不同的 caltype 返回不同的实例
                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;
                }
            }
        }
        .......
        return cal;
    }

工厂模式总结

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值