工厂模式

定义

工厂模式(Factory Method)是由一个工厂对象决定创建出哪一种产品类的实例。工厂类来封装实例化对象的行为,将产品的 “实现” 和 “使用” 解耦。

工厂模式有三类:简单工厂模式工厂方法模式抽象工厂模式

工厂模式属于类创建型模式,抽象工厂模式属于对象创建型模式。

 

要点

抽象工厂(Abstract Factory):提供创建产品的接口,调用者通过它访问具体工厂的实现方法来创建产品。
具体工厂(ConcreteFactory):实现抽象工厂中的抽象方法来完成具体产品的创建。
抽象产品(Product):定义产品规范,描述产品主要特性和功能。
具体产品(ConcreteProduct):抽象产品的特定需求来实现,由具体工厂来创建,它同具体工厂之间一一对应。

 

场景

当使用 new 实例化一个具体类时,代码绑着具体类会让代码更脆弱,缺乏弹性。在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式。

例如有披萨店,客户从 店铺点餐台(OrderPizza) 下单想要的披萨:

Pizza orderPizza(String pizzaType) {
	Pizza pizza;
	if(pizzaType.equals("Pepper")) {
		pizza = new PepperPizza();
	} else if (pizzaType.equals("Greek")) {
		pizza = new GreekPizza();
	} else if (pizzaType.equals("Cheese")) {
		pizza = new CheesePizza();
	}
	pizza.prepare();
	pizza.bake();
	pizza.cut();
	pizza.box();
	return pizza;
}

但是需求发生变化时,例如店铺上架、下架一些 Pizza ,就必须重新打开这段代码进行检查和修改,已经违反了开闭原则,而且点餐台不应该考虑披萨的制作,应该交给 后厨(披萨工厂,Factory) 负责处理。

 

实现

这里主要用代码来演示,可以在Github的链接中获取源码。

1. 简单工厂模式

简单工厂模式是由 一个工厂对象决定创建出哪一种产品类的实例 。简单工厂模式不是一个设计模式,而是一种编程习惯。

if(pizzaType.equals("Pepper")) {
	pizza = new PepperPizza();
} else if (pizzaType.equals("Greek")) {
	pizza = new GreekPizza();
} else if (pizzaType.equals("Cheese")) {
	pizza = new CheesePizza();
}

我们需要把上面的部分代码抽离出来搬到另一个对象中,这个新对象只需要负责创建 Pizza,这个新对象就是 “工厂”,OrderPizza 只需要关心从工厂得到一个披萨就行:

public class SimplePizzaFactory {

	public Pizza createPizza(String pizzaType) {
		Pizza pizza;
		switch (pizzaType) {
            case "Pepper":
                pizza = new PepperPizza();
                pizza.setPizzaName("胡椒风味披萨");
                return pizza;
            case "Greek":
                pizza = new GreekPizza();
                pizza.setPizzaName("希腊风味披萨");
                return pizza;
            case "Cheese":
                pizza = new CheesePizza();
                pizza.setPizzaName("芝士风味披萨");
                return pizza;
            default:
                return null;
        }
	}
	
}

 

示例

需求:披萨项目,需要方便披萨种类的扩展,便于维护,定义一个可以实例化 Pizaa 对象的类,封装创建对象的代码。
1)披萨的种类很多(比如 GreekPizz、CheesePizz 等)
2)披萨的制作有 prepare,bake, cut, box
3)完成披萨店订购功能。

披萨类(抽象)

/**
 * Pizza 抽象类
 */
public abstract class Pizza {

    /**
     * 披萨类型
     */
    protected String pizzaType;

    /**
     * 准备原材料, 不同的披萨不一样,做成抽象方法
     */
    public abstract void prepare();

    /**
     * 烘烤
     */
    public void bake() {
        System.out.println(pizzaType + "baking...");
    }

    /**
     * 切块
     */
    public void cut() {
        System.out.println(pizzaType + "cutting...");
    }

    /**
     * 包装
     */
    public void box() {
        System.out.println(pizzaType + "boxing...");
    }

    public void setPizzaType(String pizzaType) {
        this.pizzaType = pizzaType;
    }

}

胡椒风味披萨

/**
 * 胡椒风味披萨
 */
public class PepperPizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("给胡椒风味披萨准备原材料");
    }

}

希腊风味披萨

/**
 * 希腊风味披萨
 */
public class GreekPizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("给希腊风味披萨准备原材料");
    }

}

芝士风味披萨

/**
 * 芝士风味披萨
 */
public class CheesePizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("给芝士风味披萨准备原材料");
    }

}

简单工厂类

/**
 * 简单披萨工厂类
 */
public class SimplePizzaFactory {

    public Pizza createPizza(String pizzaType) {
        Pizza pizza;
        switch (pizzaType) {
            case "PepperPizza":
                pizza = new PepperPizza();
                pizza.setPizzaType("胡椒风味披萨");
                return pizza;
            case "GreekPizza":
                pizza = new GreekPizza();
                pizza.setPizzaType("希腊风味披萨");
                return pizza;
            case "CheesePizza":
                pizza = new CheesePizza();
                pizza.setPizzaType("芝士风味披萨");
                return pizza;
            default:
                return null;
        }
    }

}

披萨商店

/**
 * 披萨商店
 */
public class PizzaStore {

    private static final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in));

    /**
     * 给披萨商店供货的披萨工厂( 后厨 )
     */
    private SimplePizzaFactory factory;

    public PizzaStore(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    /**
     * 披萨制作流程
     */
    public void orderPizza() {
        String pizzaType;
        Pizza pizza;
        do {
            pizzaType = getType();
            // 使用简单工厂创建实例,解耦!解耦!解耦!
            pizza = this.factory.createPizza(pizzaType);

            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("披萨暂时缺货!请重新订购。");
            }
        } while (true);
    }

    /**
     * 获取客户订购的披萨种类
     *
     * @return 披萨类型
     */
    private static String getType() {
        System.out.println("\n请输入披萨类型:");
        try {
            return READER.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

}

这里的工厂,将对象实例化抽离出来,解耦。

源代码

Click here

 

2. 工厂方法模式

工厂方法模式定义了一个创建产品对象的接口,需要子类决定需要实例化的类是哪一个。工厂方法模式将对象的实例化推迟到子类。

在这里插入图片描述

示例

新需求:
有了加盟披萨店,根据加盟店地域的饮食口味不同,每家加盟店可以提供地域特色的披萨,比如 北京风味的胡椒披萨、伦敦风味的胡椒披萨。

分析:
如果使用简单工厂模式创建不同的简单工厂类,比如 BJPizzaSimpleFactory、LDPizzaSimpleFactory 等等,那么每家工厂都有了各自的制作流程,这是不行的,必须符合总店的制作流程规范才行,然后,这些加盟店可以自由地制作符合该区域特色风味的披萨。

将披萨的制作流程做成抽象方法,在不同的披萨工厂中具体实现。

北京胡椒风味披萨

/**
 * 北京胡椒风味披萨
 */
public class BJPepperPizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("给北京胡椒风味披萨准备原材料");
    }

}

伦敦胡椒风味披萨

/**
 * 伦敦胡椒风味披萨
 */
public class LDPepperPizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("给伦敦胡椒风味披萨准备原材料");
    }

}

披萨商店(抽象)

/**
 * 披萨商店(抽象)
 */
public abstract class AbstractPizzaStore {

    private static final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in));

    /**
     * 定义抽象方法createPizza, 让各个工厂子类自己实现当地的特色风味披萨
     */
    protected abstract Pizza createPizza(String pizzaType);

    /**
     * 披萨制作流程,所有的加盟店都需要遵守
     */
    protected final void orderPizza() {
        String pizzaType;
        Pizza pizza;
        do {
            pizzaType = getType();
            // 顾客决定工厂,子类工厂决定披萨,解耦!解耦!解耦!
            pizza = createPizza(pizzaType);

            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("披萨暂时缺货!请重新订购。");
            }
        } while (true);
    }

    /**
     * 获取客户订购的披萨种类
     *
     * @return 披萨类型
     */
    private String getType() {
        System.out.println("\n请输入披萨类型:");
        try {
            return READER.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
}

北京披萨商店

/**
 * 北京披萨商店
 */
public class BJPizzaStore extends AbstractPizzaStore {

    @Override
    public Pizza createPizza(String pizzaType) {
        Pizza pizza;
        switch (pizzaType) {
            case "PepperPizza":
                pizza = new BJPepperPizza();
                pizza.setPizzaType("北京胡椒风味披萨");
                return pizza;
            case "GreekPizza":
                pizza = new BJGreekPizza();
                pizza.setPizzaType("北京希腊风味披萨");
                return pizza;
            case "CheesePizza":
                pizza = new BJCheesePizza();
                pizza.setPizzaType("北京芝士风味披萨");
                return pizza;
            default:
                return null;
        }
    }

}

伦敦披萨商店

/**
 * 伦敦披萨商店
 */
public class LDPizzaStore extends AbstractPizzaStore {

    @Override
    public Pizza createPizza(String pizzaType) {
        Pizza pizza;
        switch (pizzaType) {
            case "PepperPizza":
                pizza = new LDPepperPizza();
                pizza.setPizzaType("伦敦胡椒风味披萨");
                return pizza;
            case "GreekPizza":
                pizza = new LDGreekPizza();
                pizza.setPizzaType("伦敦希腊风味披萨");
                return pizza;
            case "CheesePizza":
                pizza = new LDCheesePizza();
                pizza.setPizzaType("伦敦芝士风味披萨");
                return pizza;
            default:
                return null;
        }
    }

}

这里的工厂生产一种产品,那就是披萨。

源代码

Click here

 

3. 抽象工厂模式

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而无需指明具体的类。

抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么,客户就从具体的产品中被解耦。

在这里插入图片描述

示例

需求:
工厂模式让所有加盟店使用总店的制作流程规范,为了防止加盟店使用廉价的食材增加利润,这可能会损害品牌形象,我们需要建立一家原料工厂来防止这样的事情发生。但是,不同地域的食材可能是不一样的。

这次的工厂面向的是披萨原料。

酱料

/**
 * 酱料类型
 */
public interface Sauce {

    /**
     * 获取酱料类型名
     */
    String getSauceType();

}
/**
 * 面团类型
 */
public interface Dough {

    /**
     * 获取面团类型名
     */
    String getDoughType();

}
/**
 * 芝士类型
 */
public interface Cheese {

    /**
     * 获取芝士类型名
     */
    String getCheeseType();

}

披萨(抽象)

/**
 * 披萨(抽象)
 */
public abstract class AbstractPizza {

    /**
     * 披萨类型
     */
    protected String pizzaType;
    /**
     * 披萨的酱料
     */
    protected Sauce sauce;
    /**
     * 披萨的面团
     */
    protected Dough dough;
    /**
     * 披萨的芝士
     */
    protected Cheese cheese;

    /**
     * 基本的做法(具体种类的披萨去实现)
     */
    public abstract void prepare();

    /**
     * 烘烤
     */
    public void bake() {
        System.out.println( pizzaType + "baking...");
    }

    /**
     * 切块
     */
    public void cut() {
        System.out.println(pizzaType + "cutting...");
    }

    /**
     * 包装
     */
    public void box() {
        System.out.println(pizzaType + "boxing...");
    }

    public void setPizzaType(String pizzaType) {
        this.pizzaType = pizzaType;
    }

}

北京风味的芝士披萨

/**
 * 北京风味的芝士披萨
 */
public class BJCheesePizza extends AbstractPizza {

    private PizzaIngredientFactory ingredientFactory;

    public BJCheesePizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }

    @Override
    public void prepare() {
        System.out.println(pizzaType + " preparing...");
        sauce = ingredientFactory.createSauce();
        System.out.println("sauce: " + sauce.getSauceType());
        dough = ingredientFactory.createDough();
        System.out.println("dough: " + dough.getDoughType());
        cheese = ingredientFactory.createCheese();
        System.out.println("cheese: " + cheese.getCheeseType() + "\n");
    }

}

伦敦风味的芝士披萨

/**
 * 伦敦风味的芝士披萨
 */
public class LDCheesePizza extends AbstractPizza {

    private PizzaIngredientFactory ingredientFactory;

    public LDCheesePizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }

    @Override
    public void prepare() {
        System.out.println(pizzaType + " preparing...");
        sauce = ingredientFactory.createSauce();
        System.out.println("sauce: " + sauce.getSauceType());
        dough = ingredientFactory.createDough();
        System.out.println("dough: " + dough.getDoughType());
        cheese = ingredientFactory.createCheese();
        System.out.println("cheese: " + cheese.getCheeseType() + "\n");
    }
}

披萨商店(抽象)

/**
 * 披萨商店(抽象)
 */
public abstract class AbstractPizzaStore {

    private static final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in));

    /**
     * 让子类自己实现
     */
    protected abstract AbstractPizza createPizza(String pizzaType);

    /**
     * 披萨制作流程
     */
    protected final void orderPizza() {
        String pizzaType;
        AbstractPizza pizza;
        do {
            pizzaType = getType();
            pizza = createPizza(pizzaType);

            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("披萨暂时缺货!请重新订购。");
            }
        } while (true);
    }

    /**
     * 获取客户订购的披萨种类
     *
     * @return 披萨类型
     */
    private String getType() {
        System.out.println("\n请输入披萨类型:");
        try {
            return READER.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
}

伦敦披萨商店

/**
 * 伦敦披萨商店
 */
public class BJPizzaStore extends AbstractPizzaStore {

    private PizzaIngredientFactory ingredientFactory = new BJPizzaIngredientFactory();

    @Override
    protected AbstractPizza createPizza(String pizzaType) {
        AbstractPizza pizza;

        switch (pizzaType) {
            case "CheesePizza":
                pizza = new BJCheesePizza(ingredientFactory);
                pizza.setPizzaType("北京芝士风味披萨");
                return pizza;
            default:
                return null;
        }
    }

}

伦敦披萨商店

/**
 * 伦敦披萨商店
 */
public class LDPizzaStore extends AbstractPizzaStore {

    private PizzaIngredientFactory ingredientFactory = new LDPizzaIngredientFactory();

    @Override
    protected AbstractPizza createPizza(String pizzaType) {
        AbstractPizza pizza;

        switch (pizzaType) {
            case "CheesePizza":
                pizza = new LDCheesePizza(ingredientFactory);
                pizza.setPizzaType("伦敦风味披萨");
                return pizza;
            default:
                return null;
        }
    }

}

食材工厂定义接口(抽象工厂)

/**
 * 为食材工厂定义接口
 */
public interface PizzaIngredientFactory {

    /**
     * 面团
     */
    Dough createDough();

    /**
     * 酱料
     */
    Sauce createSauce();

    /**
     * 芝士
     */
    Cheese createCheese();

}

北京披萨食材工厂

/**
 * 北京披萨食材工厂
 */
public class BJPizzaIngredientFactory implements PizzaIngredientFactory {

    @Override
    public Sauce createSauce() {
        return new MarinaraSauce();
    }

    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }

}

伦敦披萨食材工厂

/**
 * 伦敦披萨食材工厂
 */
public class LDPizzaIngredientFactory implements PizzaIngredientFactory {

    @Override
    public Sauce createSauce() {
        return new PlumTomatoSauce();
    }

    @Override
    public Dough createDough() {
        return new ThickCrustDough();
    }

    @Override
    public Cheese createCheese() {
        return new MozzarellaCheese();
    }

}

这里的食材工厂可以生产多种食材,而不是一种食材。

源代码

Click here

 

总结

使用工厂模式的好处在于面向接口编程,它可以将产品的 “使用” 和 “生产” 解耦,将创建对象的代码集中在一个地方,可以避免代码中的重复,方便后期维护。工厂模式很好地结合了 依赖倒置原则(要依赖抽象,不要依赖具体) ,想要遵循依赖倒置原则,工厂方法是很好的技巧。

  • 所有的工厂都是用来封装对象的创建。
  • 所有工厂模式都通过减少应用程序和具体类之间的依赖实现松耦合。
  • 工厂方法模式使用继承形式,对象的创建延迟到子类进行
  • 工厂方法模式创建一类产品,子类实现工厂方法来创建对象。
  • 抽象工厂模式使用对象组合形式,对象的创建被实现在工厂接口所暴露出来的方法中
  • 抽象工厂模式创建相关的产品家族,而不需要依赖它们的具体类。

举例:在JDK的 Calender 日期类中就使用工厂模式来创建不同的日期实例类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值