《Head First 设计模式》:工厂方法模式

本贴最后更新于 1346 天前,其中的信息可能已经水流花落

正文

一、定义

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

PS:在设计模式中,“实现一个接口”泛指实现某个超类型(可以是类或接口)的某个方法。

要点:

  • 通过子类来创建具体的对象。客户只需要知道他们所使用的抽象类型即可。
  • 由子类决定要实例化的类是哪一个,是指在编写创建者类时,不需要知道实际创建的产品是哪一个。选择了使用哪个创建者子类,自然就决定了实际创建的产品是什么。
  • 对象统一由定义好的工厂方法来创建。

二、实现步骤

1、创建产品抽象类

/**
 * 产品抽象类
 */
public abstract class Product {
    
    String name;
    
    public String getName() {
        return name;
    }
}

2、创建具体的产品,并继承产品抽象类

(1)产品 A1

/**
 * 产品A1
 */
public class ConcreteProductA1 extends Product {
    
    public ConcreteProductA1() {
        name = "ConcreteProductA1";
    }
}

(2)产品 A2

/**
 * 产品A2
 */
public class ConcreteProductA2 extends Product {
    
    public ConcreteProductA2() {
        name = "ConcreteProductA2";
    }
}

(3)产品 B1

/**
 * 产品B1
 */
public class ConcreteProductB1 extends Product {
    
    public ConcreteProductB1() {
        name = "ConcreteProductB1";
    }
}

(4)产品 B2

/**
 * 产品B2
 */
public class ConcreteProductB2 extends Product {
    
    public ConcreteProductB2() {
        name = "ConcreteProductB2";
    }
}

3、创建创建者抽象类,并定义用来创建产品的工厂方法

创建者一般为需要用到产品的类,需要的产品则通过类中的工厂方法创建。

/**
 * 创建者抽象类
 */
public abstract class Creator {

    /**
     * 创建产品(工厂方法)
     */
    protected abstract Product createProduct(String productType);
}

4、创建具体的创建者,并继承创建者抽象类

具体的创建者需要实现创建产品的工厂方法。

(1)创建者 1

/**
 * 创建者1
 */
public class ConcreteCreator1 extends Creator {

    @Override
    protected Product createProduct(String productType) {
        // 由具体的创建者(子类)决定创建哪个类的对象
        if ("A".equals(productType)) {
            return new ConcreteProductA1();
        } else if ("B".equals(productType)) {
            return new ConcreteProductB1();
        }
        return null;
    }
}

(2)创建者 2

/**
 * 创建者2
 */
public class ConcreteCreator2 extends Creator {

    @Override
    protected Product createProduct(String productType) {
        // 由具体的创建者(子类)决定创建哪个类的对象
        if ("A".equals(productType)) {
            return new ConcreteProductA2();
        } else if ("B".equals(productType)) {
            return new ConcreteProductB2();
        }
        return null;
    }
}

5、创建者通过工厂方法创建产品

public class Test {
    
    public static void main(String[] args) {
        // 创建者1
        Creator creator1 = new ConcreteCreator1();
        // 创建者2
        Creator creator2 = new ConcreteCreator2();
        
        // 通过工厂方法创建产品
        Product product = creator1.createProduct("A");
        System.out.println("创建者1创建产品A:" + product.getName());
        product = creator2.createProduct("A");
        System.out.println("创建者2创建产品A:" + product.getName());
    }
}

三、举个栗子

1、背景

假设你有一个披萨店,出售多种类型的披萨:芝士披萨、蛤蜊披萨、素食披萨等。由于经营有成,你打算推广自己的加盟店。

为了确保加盟店运营的质量,你希望加盟店能够采用固定的制作流程。但是由于区域的差异,每家加盟店都可能想要提供不同风味的披萨(比如纽约、芝加哥、加州),因此又必须允许加盟店能够自由地制作该区域的风味。

2、实现

披萨店子类通过实现创建披萨方法来决定要创建什么风味的披萨。

(1)创建披萨抽象类

/**
 * 披萨抽象类
 */
public abstract class Pizza {
    
    /**
     * 名称
     */
    String name;
    /**
     * 面团
     */
    String dough;
    /**
     * 酱料
     */
    String sauce;
    /**
     * 佐料
     */
    ArrayList<String> toppings = new ArrayList<>();
    
    void prepare() {
        System.out.println("Preparing " + name);
        System.out.println("Tossing dough...");
        System.out.println("Adding souce...");
        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;
    }
}

(2)创建不同风味、不同类型的披萨

/**
 * 纽约风味的芝士披萨
 */
public class NYStyleCheesePizza extends Pizza {

    public NYStyleCheesePizza() {
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
        toppings.add("Grated Reggiano Cheese");
    }
}
/**
 * 纽约风味的蛤蜊披萨
 */
public class NYStyleClamPizza extends Pizza {

    public NYStyleClamPizza() {
        name = "NY Style Sauce Clam Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
        toppings.add("Fresh Clams");
    }
}
/**
 * 芝加哥风味的芝士披萨
 */
public class ChicagoStyleCheesePizza extends Pizza {

    public ChicagoStyleCheesePizza() {
        name = "Chicago Style Deep Dish Cheese Pizza";
        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");
    }
}
/**
 * 芝加哥风味的蛤蜊披萨
 */
public class ChicagoStyleClamPizza extends Pizza {

    public ChicagoStyleClamPizza() {
        name = "Chicago Style Clam Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";
        toppings.add("Frozen Clams");
    }
    
    void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}

(3)创建披萨店抽象类

/**
 * 披萨店抽象类
 */
public abstract class PizzaStore {
    
    /**
     * 订购披萨
     */
    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    
    /**
     * 创建披萨(工厂方法)
     */
    protected abstract Pizza createPizza(String type);
}

(4)创建不同风味的披萨店

/**
 * 纽约风味披萨店
 */
public class NYStylePizzaStore extends PizzaStore {

    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        if ("cheese".equals(type)) {
            pizza = new NYStyleCheesePizza(); 
        } else if ("clam".equals(type)) {
            pizza = new NYStyleClamPizza();
        }
        return pizza;
    }
}
/**
 * 芝加哥风味披萨店
 */
public class ChicagoStylePizzaStore extends PizzaStore {

    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        if ("cheese".equals(type)) {
            pizza = new ChicagoStyleCheesePizza(); 
        } else if ("clam".equals(type)) {
            pizza = new ChicagoStyleClamPizza();
        }
        return pizza;
    }
}

(5)使用不同风味的披萨店订购披萨

public class Test {
    
    public static void main(String[] args) {
        // 纽约风味披萨店
        PizzaStore nyStore = new NYStylePizzaStore();
        // 芝加哥风味披萨店
        PizzaStore chicagoStore = new ChicagoStylePizzaStore();
        
        // 订购芝士披萨
        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");
    }
}
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    198 引用 • 120 回帖
1 操作
jingqueyimu 在 2020-07-20 23:14:01 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...