设计模式 | 04 工厂方法模式

本贴最后更新于 1687 天前,其中的信息可能已经时移世异

开头说几句

博主的博客地址:https://www.jeffcc.top/
推荐入门学习设计模式 java 版本的数据 Head First 《设计模式》

什么是工厂方法模式

专业定义:工厂方法模式定义了一个创建对象的接口,但是由子类决定实例化的类是哪一个。工厂方法让实例化延迟到了子类。
博主的理解:工厂方法其实也是使用了把不变的部分和变化的部分分开封装起来的设计原则,将变化的部分提供一个抽象方法来交给子类来实现,不变的部分由工厂完成封装。
这种设计可以将对象的创建封装起来,以便得到更加松耦合,更有弹性的设计。

设计原则

  1. 依赖倒置原则,要依赖抽象,不要依赖具体类,具体做法是需要高层组件(工厂)和底层组件(实现类)之间不要有太多的依赖关系,而是可以通过一个共同的抽象类(工厂产生的对象)来实现依赖倒置。
  2. 多用组合,少用继承。
  3. 针对接口编程,而不是针对实现编程。
  4. 为交互对象之间的松耦合设计而努力。
  5. 类应该对外开放拓展,对修改关闭。

设计要点

  1. 所有的工厂都是用来封装对象的创建的。
  2. 工厂方法使用继承,把对象的创建委托给子类,子类实现工厂方法来创建对象。
  3. 工厂方法允许类的实例化延迟到子类。

设计实现

设计背景

一家披萨店需要拓展加盟业务,届时会有许多不同地方口味的披萨出现,而我们需要做的就是设计一个工厂来让加盟商使用,具体的风味的披萨由加盟商自己决定,工厂只负责包装等内容。

代码实现

项目结构

image.png

项目类图

image.png

披萨工厂
package factory;

import pizza.Pizza;

/**
 * 披萨工厂
 */
public abstract class PizzaStore {

    public Pizza orderPizza(String type){
        Pizza pizza;
//        进行创建pizza
        pizza = createPizza(type);
//        下面进行的是共同的东西,所以封装起来到工厂中
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;

    }

    /**
     * 抽取出一个抽象的制作pizza的方法来交给子类具体实现
     * 工厂模式的关键所在
     * @param type  什么风味的pizza
     * @return
     */
    public abstract Pizza createPizza(String type);

}

ChicagoPizzaStore 加盟店
package store;

import factory.PizzaStore;
import pizza.Pizza;
import pizza.impl.ChicagoStyleCheesePizza;

/**
 * ChicagoPizzaStore加盟店
 */
public class ChicagoPizzaStore extends PizzaStore {

    /**
     * 模拟测试生产pizza  太多类型了就写一个 理论可以无限拓展
     * @param type 什么风味的pizza
     * @return
     */
    @Override
    public Pizza createPizza(String type) {
        if ("cheese".equals(type)) {
            return new ChicagoStyleCheesePizza();
        } else {
            return null;
        }
    }
}

NYpizza 加盟店
package store;

import factory.PizzaStore;
import pizza.Pizza;
import pizza.impl.NYStyleCheesePizza;

/**
 * 纽约pizza加盟店
 */
public class NYPizzaStore extends PizzaStore {

    /**
     * 模拟测试生产pizza  太多类型了就写一个 理论可以无限拓展
     * @param type 什么风味的pizza
     * @return
     */
    @Override
    public Pizza createPizza(String type) {
        if ("cheese".equals(type)) {
            return new NYStyleCheesePizza();
        } else {
            return null;
        }
    }
}

披萨抽象类(关键)
package pizza;

import java.util.ArrayList;

/**
 * pizza的抽象类
 * 也就是之前说的依赖倒置所依赖的类!!!
 * 需要有pizza的操作的方法
 */
public abstract class Pizza {

    public String name;//pizza名称
    public String dough;//pizza面团类型
    public String suace;//pizza酱料类型
    public ArrayList<String> toppings = new ArrayList<>(); //佐料


    /**
     * 提供默认的基本做法 进行烘烤、切片、装盒 如果需要可以进行重写
     */
    public void prepare() {
        System.out.println("Preparing" + name);
        System.out.println("Tossing dough...");
        System.out.println("Adding toppings:");
        toppings.forEach(topping -> {
            System.out.println("  " + topping);
        });

    }

    /**
     * 烘烤
     */
    public void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }

    /**
     * 切片
     */
    public void cut() {
        System.out.println("Cutting the pizza into diagonal slices!");
    }

    /**
     * 装盒
     */
    public void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    public String getName() {
        return name;
    }
}

ChicagoStyleCheesePizza
package pizza.impl;

import pizza.Pizza;

/**
 * 实现不同的风味的pizza ChicagoStyleCheesePizza
 */
public class ChicagoStyleCheesePizza extends Pizza {


    /**
     * 设置风味
     */
    public ChicagoStyleCheesePizza() {
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Curst Dough";
        suace = "Plum Tomato Suace";
        toppings.add("Shredded Mozzarella Cheese");
    }


    /**
     * 模拟需要有不同的切片方法
     */
    @Override
    public void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}

NYStyleCheesePizza
package pizza.impl;

import pizza.Pizza;

/**
 * 实现不同的风味的pizza 纽约风味
 */
public class NYStyleCheesePizza extends Pizza {

    /**
     * 设置风味
     */
    public NYStyleCheesePizza() {
        name = "NY Style Sauce and Cheese Pizza";
        dough="Thin Curst Dough";
        suace="Marinara Suace";
        toppings.add("Grated Reggiano Cheese");
    }
}

测试买 pizza
package test;

import factory.PizzaStore;
import pizza.Pizza;
import store.ChicagoPizzaStore;
import store.NYPizzaStore;

public class BuyPizza {
    public static void main(String[] args) {

//        找到NY店
        PizzaStore nyPizzaStore = new NYPizzaStore();
        Pizza pizza1 = nyPizzaStore.orderPizza("cheese");
        System.out.println("jay order a "+pizza1.getName()+"\n");

//        Chicago店
        PizzaStore chicagoPizzaStore = new ChicagoPizzaStore();
        Pizza pizza2 = chicagoPizzaStore.orderPizza("cheese");
        System.out.println("jeff order a "+pizza2.getName()+"\n");
    }
}

输出结果

image.png

最后说两句

工厂方法让子类决定要实例化的类是哪一个,这句话的理解并不是指模式允许子类本身在运行时做出决定,而是要在编写创建者类的时候,不需要知道实际所创建的产品是哪一个,选择了使用哪一个子类,也就“决定”了实际创建的产品是什么。
接下来会出一篇关于抽象工厂模式的文章 和工厂方法模式有一定的相通性。


END
2019 年 9 月 4 日 09:20:13

  • 设计模式

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

    198 引用 • 120 回帖

相关帖子

欢迎来到这里!

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

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