工厂模式读书笔记

简单工厂模式

在我们平时的编码过程中,我们会经常使用到new,而当我们使用new的时候,就会想到"具体",因为我们的确是在实例化一个具体类,这样子,可能会导致代码更脆弱。比如说,我们可能会写出以下代码:

Duck duck;
if(picnic){
duck = new MallardDuck();
}else if (hunting){
duck = new DecoyDuck();
}else if(inBathTub){
duck = new RubberDuck();
}

当出现这种代码时,一旦需求有变化,就必须重新打开这段代码进行检查和修改。通常这样修改过的diam将造成部分系统更难维护和更新,而且更容易犯错。

披萨的例子

当我们订购一个披萨的时候,我们可能会写出如下代码:

public class PizzaStore{
    Pizza orderPizza(String type){
    	Pizza pizza;
    	//根据披萨的类型,我们实例化正确的具体类
    	if(type.equals("cheese")){
    		pizza = new CheesePizza();
    	}else if(type.equals("greek")){
    		pizza = new GreekPizza();
    	}else if(type.equals("pepperoni")){
    		pizza = new PepperoniPizza();
    	}
	    pizza.prepare();
	    pizza.bake();
	    pizza.cut();
	    pizza.box();
	    return pizza;
    }
}

但是一旦我们pizza的种类变化,我们就不得不修改if else语句。因此我们需要把这一部分进行封装。

建立简单工厂
public class SimplePizzaFactory{
	public Pizza createPizza(String type){
		Pizza pizza = null;
		if(type.equals("cheese")){
    		pizza = new CheesePizza();
    	}else if(type.equals("greek")){
    		pizza = new GreekPizza();
    	}else if(type.equals("pepperoni")){
    		pizza = new PepperoniPizza();
    	}
		return pizza;
	}
}

除此之外,我们还可以将工厂定义为静态方法,这是我们常见的一个技巧,因为不需要使用创建对象的方法来实例化对象,但是这也有确定,不能通过集成来改变创建方法的行为。

我们的PizzaStore变成了如下:

 public class PizzaStore{
    SimplePizzaFactory factory;
	public PizzaStore(SimplePizzaFactory factory){
		this.factory = factory;
	}
      Pizza orderPizza(String type){
        	Pizza pizza;
        	pizza = factory.createPizza(type);
    	    pizza.prepare();
    	    pizza.bake();
    	    pizza.cut();
    	    pizza.box();
    	    return pizza;
        }
    }
kotlin实现
class SimpleFactory {
    fun createPizza(type : String) : Pizza{
        lateinit var pizza : Pizza
        if (type == "NY"){
            pizza = NYPizza()
        }else if (type == "Chi"){
            pizza = ChiPizza()
        }
        return pizza
    }
}
class PizzaStore constructor(factory : SimpleFactory){
    private var factory : SimpleFactory = factory
    fun orderPizza(type : String) : Pizza{
        val pizza = factory.createPizza(type)
        pizza.bake()
        pizza.prepare()
        return pizza
    }
}
定义简单工厂

简单工厂其实不是一个设计模式,它比较像是一种编程习惯,但是我们会经常用到它。

工厂模式

假设我们又增加了新的需求,我们的pizza店需要生产更多的披萨,我们需要根据不同区域的口味,生成不同种类的披萨,这时我们的PizzaStore就会变成这样
在这里插入图片描述
这样就会有越来越多的工厂,分别产生不同口味的披萨。因此,我们可以通过创建多个“披萨店”分别制造不同口味的披萨,除此之外,我们加工披萨的流程也会产生差异,因此我们需要对我们的pizzaStore做出些改变,将加工pizza的流程和pizza的制作流程捆绑在一起的同时又具有一定弹性。

代码

我们的PizzaStore现在变成了这样:

PizzaStore.java

public abstract class PizzaStore {

    // 原本是由一个类类负责所有具体类的实例化,现在变成由一堆子类来负责实例化

    public Pizza orderPizza(String type){
        Pizza pizza;
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

    protected abstract Pizza createPizza(String type);//工厂方法是抽象的,所以依赖子类来处理对象的创建。 工厂方法必须返回一个对象
}

NYPizzaStore.java

public class NYPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        if (type.equals("cheese")){
            return new NYStyleCheesePizza();
        }else if (type.equals("veggie")){
            return new NYStyleVeggiePizza();
        }else {
            return null;
        }
    }
}

ChicagoPizzaStore.java

public class ChicagoPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        if (type.equals("cheese")){
            return new ChicagoStyleCheesePizza();
        }else {
            return null;
        }
    }
}

我们让PizzaStore的各个子类负责定义自己的createPizza()方法,所以我们会得到一些PizzaStore具体的子类。

在这里插入图片描述

那子类是如何做决定的呢?当orderPizza()调用createPizza()方法的时候,某个披萨店的子类(NYStylePizzaStore或者ChicagoStylePizzaStore)来负责创建披萨。

下面,我们看一下我们的Pizza类:
Pizza.java

import java.util.ArrayList;

public abstract class Pizza {

    String name;
    String dough;
    String sauce;

    ArrayList toppings = new ArrayList();

    void prepare(){
        System.out.println("Preparing " + name );
        System.out.println("Tossing dough...");
        System.out.println("Ading sauce...");
        System.out.println("Adding toppings: ");
        for (int i = 0; i < toppings.size(); i++){
            System.out.println(" " + toppings.get(i));
        }
    }

    void bake(){
        System.out.println("Bake for 25 minutes at 350");
    }

    void cut(){
        System.out.println("Cutting the pizza into diagonal slices");
    }

    void box(){
        System.out.println("Place pizza in official PizzaStore box");
    }

    public String getName() {
        return name;
    }
}

现在我们需要一些具体子类,来定义纽约和芝加哥风味的芝士披萨。
芝加哥风味的:
ChicagoStyleCheesePizza.java

public class ChicagoStyleCheesePizza extends Pizza {
    public ChicagoStyleCheesePizza(){
        name = "Chicago Style Deep Dish Cheese Pizzza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";
        toppings.add("Shredded Mozzarella Cheese");
    }

    void cut(){
        System.out.println("Cutting the pizza into square slices");
    }
}

纽约风味的
NYStyleCheesePizza.java

public class NYStyleCheesePizza extends Pizza {

    public NYStyleCheesePizza(){
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Cruse Dough";
        sauce = "Marinara Sauce";
        toppings.add("Grated Reggiano Cheese");
    }
}

NYStyleVeggiePizza.java

public class NYStyleVeggiePizza extends Pizza {

    public NYStyleVeggiePizza(){
        name = "NY Style Sauce and Veggie Pizza";
        dough = "Thin Cruse Dough";
        sauce = "Marinara Sauce";
        toppings.add("Grated Reggiano Veggie");
    }
}

测试类:

public class PizzaTestDrive {
    public static void main(String[] args){
        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();

        Pizza pizza = nyStore.orderPizza("cheese");
        System.out.println("Ethan ordered a "+ pizza.getName() + "\n");

        pizza = chicagoStore.orderPizza("cheese");
        System.out.println("Joel Ordered a "+ pizza.getName() + "\n");
    }
}

工厂模式类图

创建者类:
在这里插入图片描述
所有工厂模式都是用来封装对象的创建。工厂模式通过让子类决定该创建对象是什么,来达到将对象创建的过程封装的目的。
PizzaStore里面定义了一个抽象的工厂方法createPizza(),让子类实现此方法,来制造产品。这些子类称为具体创建者。

产品类:

在这里插入图片描述
上图这些就是具体的产品。

定义工厂模式

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

工厂模式类图

在这里插入图片描述

所有的产品必须实现这个共同的接口Product,这样,使用这些产品的类就可以引用这个接口,而不是具体类。
Creator是一个类,它实现了所有操纵产品的方法,但是它不实现工厂方法。Creator的子类必须实现factoryMethod这个抽象方法,来实际制造出产品。ConcreteCreator类负责创建一个或多个具体的ConcreteProduct。

工厂模式和简单工厂比较

简单工厂的做法,可以将对象的创建封装起来,在一个地方都处理完了;但是工厂方法只是提供了一个框架,由子类决定要如何实现。

依赖倒置原则

不能让高层组件依赖底层组件,无论是高层组件还是底层组件,都应该依赖于抽象。

抽象工厂

我们的披萨制造过程中是由不同的原料组成的,纽约风味的披萨使用一组原料,而芝加哥使用另一组原料。每一种原料都包含一种棉短,一种酱料,一种芝士以及一种海鲜。因此,我们需要处理一下这些原料。

建造原料工厂

public interface PizzaIngredientFactory {
    public Dough createDough();
    public Sauce createSauce();
    public Cheese createCheese();
    public Veggies[] createVeggies();
    public Pepperoni createPepperoni();
    public Clams createClam();
}

在这个接口中,每个原料都有一个对应的方法创建该原料。我们要做的是,为每一种区域都建造一个工厂,比如说,我们先创建纽约原料工厂。

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }

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

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

    @Override
    public Veggies[] createVeggies() {
        Viggies viggies[] = {new Garlic(), new Onion(),new MushRoom()};
        return viggies;
    }

    @Override
    public Pepperoni createPepperoni() {
        return new SlicedPepperoni();
    }

    @Override
    public Clams createClam() {
        return new FreshClams();
    }
}

重做pizza

import java.util.ArrayList;

public abstract class Pizza {

    String name;
    Dough dough;
    Sause sauce;

    ArrayList toppings = new ArrayList();

   abstract void prepare();

    void bake(){
        System.out.println("Bake for 25 minutes at 350");
    }

    void cut(){
        System.out.println("Cutting the pizza into diagonal slices");
    }

    void box(){
        System.out.println("Place pizza in official PizzaStore box");
    }

    public String getName() {
        return name;
    }
}

重做CheesePizza

public class CheesePizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;
    public CheesePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    @Override
    void prepare() {
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
    }
}

再看我们的披萨店

public class NYPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        // 纽约店会用到纽约披萨原料工厂,由该工厂负责生产所有纽约风味比萨所需的原料。
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        if (type.equals("cheese")){
            pizza = new CheesePizza(ingredientFactory);
            return pizza;
        }else if (type.equals("veggie")){
            // TODO 
            
        }
    }
}

我们公共抽象工厂所提供的接口,可以创建产品家族,利用这个接口,我们的代码将从实际的工厂解耦。

定义抽象工厂模式

抽象工厂模式提供了一个接口,用于创建相关或依赖对象的家族,而不需要明确指明具体类。
在这里插入图片描述
从图中可以看出,抽象工厂的任务是定义一个负责创建一组产品的接口,这个接口内的每个方法都负责创建一个具体产品。同时,我们利用实现抽象工厂的子类来提供这些具体的做法,所以,在抽象工厂中利用工厂方法实现生产方法是相当自然的做法。

比较工厂方法和抽象工厂

工厂方法和抽象工厂都是负责创建对象,但是工厂方法使用的是继承,但是抽象工厂使用的是对象的组合。这就意味着,利用工厂方法创建对象,需要扩展一个类,并覆盖他的工厂方法。但是抽象工厂提供了一个用来创建一个产品家族的抽象类型,这个类型的子类定义了产品被产生的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值