零.前言
HeadFirst设计模式学习笔记(1)——工厂模式
2022/7/18
2022/11/22
2022/11/27.28
2022/11/29总结
0.1.组织结构
本文的组织结构分为简单工厂模式和工厂模式,并以披萨店的品类、加盟和原料为例介绍它们。通过本文你可以学到:
● OO原则“对扩展开放对修改关闭”
● 简单工厂模式
● 工厂模式
● 构造器方式的依赖注入
● 依赖倒置原则
● 抽象工厂模式
0.2.工厂模式
工厂模式(Factory Pattern)现在是JAVA中最常用的设计模式之一。属于创建型模式,提供了一种创建对象的最佳方式。它通过一个工具类,将创建对象的具体逻辑隐藏起来,方便对外调用,也方便修改和维护。
0.3.思维导图
一、简单工厂模式
1.1.Pizza类
根据OO原则“对扩展开放,对修改关闭”,对Pizza采用抽象类/接口,通过多态与任何新类实现抽象类/该接口。
abstract class Pizza{
String name;
String dough;
String sauce;
void prepare(){
//姓名、调料、面团之类的准备
System.out.println("准备材料完毕!");
}
void bake(){
System.out.println("bake over!");
}
void cut(){
System.out.println("cut over!");
}
void box(){
System.out.println("box over!");
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDough() {
return dough;
}
public void setDough(String dough) {
this.dough = dough;
}
public String getSauce() {
return sauce;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
}
Pizza pizza = new Pizza();//实现的方式
披萨实例更多时,就需要判断并生成对象
if(type.equals("cheese")){//奶酪
pizza = new CheesePizza("cheese");
}else if(type.equals("greek")){//希腊
pizza = new GreekPizza("greek");
}else if(type.equals("pepperoni")){//香肠
pizza = new PeppernoiPizza("pepperoni");
}
但是这种写法只有在运行时,才知道该实例化哪一个,且代码在新增/减少功能时需要多次更改。如添加type,“clam”,或者将现有需求中的"greek"删去。
提醒: 在设计模式中,“实现一个接口”并不一定表示“写一个类,并利用implement关键词来实现某个Java接口”。“实现一接口”泛指实现某个超类型(可以是类或接口)的某个方法。对Pizza采用抽象类/接口的表述也是这个意思。
1.2.SimplePizzaFactory类
建立一个简单的披萨工厂,专门负责创建这些Pizza对象。具体来说实现了简单工厂中的createPizza()方法,用这个方法来实例化新Pizza对象。
//SimplePizzaFactory,创建披萨
public class SimplePizzaFactory{
public Pizza createPizza(String type){
Pizza pizza = null;
//上述代码段
if(type.equals("cheese")){//奶酪
pizza = new CheesePizza("cheese");
}else if(type.equals("greek")){//希腊
pizza = new GreekPizza("greek");
}else if(type.equals("pepperoni")){//香肠
pizza = new PeppernoiPizza("pepperoni");
}
}
}
1.3.完整代码
public class orginPizza {
public static void main(String[] args) {//我们来个奶酪披萨
Pizza pizza;
SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();
pizza = simplePizzaFactory.createPizza("cheese");
System.out.println(pizza.getName()+"Pizza准备完毕!");
}
}
class SimplePizzaFactory{
public Pizza createPizza(String type){
Pizza pizza = null;
if(type.equals("cheese")){
pizza = new CheesePizza("cheese");
}else if(type.equals("greek")){
pizza = new GreekPizza("greek");
}else if(type.equals("pepperoni")){
pizza = new PeppernoiPizza("pepperoni");
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
abstract class Pizza{
String name;
String dough;
String sauce;
void prepare(){
//姓名、调料、面团之类的准备
System.out.println("准备材料完毕!");
}
void bake(){
System.out.println("bake over!");
}
void cut(){
System.out.println("cut over!");
}
void box(){
System.out.println("box over!");
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDough() {
return dough;
}
public void setDough(String dough) {
this.dough = dough;
}
public String getSauce() {
return sauce;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
}
/*
抽象类先继承,再实例化
*/
class CheesePizza extends Pizza{
private String name;
public CheesePizza(){};
public CheesePizza(String name){
this.name = name;
}
@Override
public String getName() {
return name;
}
}
class GreekPizza extends Pizza{
private String name;
public GreekPizza(){};
public GreekPizza(String name){
this.name = name;
}
@Override
public String getName() {
return name;
}
}
class PeppernoiPizza extends Pizza{
private String name;
public PeppernoiPizza(){};
public PeppernoiPizza(String name){
this.name = name;
}
@Override
public String getName() {
return name;
}
}
1.4.输出
准备材料完毕!
bake over!
cut over!
box over!
cheesePizza准备完毕!
1.5、特点
SimplePizzaFactory是一个非接口抽象类,所用的createPizza通常是静态的,所以也称作静态工厂。
1.6、缺点
1、扩展性差(改变品类如,添加type,“clam”,或者将现有需求中的"greek"删去。)
2、无法支持需要额外参数的情况,如需要新增“风格”参数,则需要更多的if,else
二、工厂模式
工厂模式即定义了一个创建对象的接口,但由子类决定要实例化的是哪一个。
2.1.披萨定义
建立PizzaStore工厂创建披萨
工厂调用orderPizza、然后简单工厂去调用createPizza生产披萨,而不是在PizzaFactory中直接创建披萨,这种处理也称作依赖注入,是通过构造器方式注入。
public class PizzaStore{
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory){
this.factory = factory;
}
public Pizza orderPizza(String type){
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
完整代码
public class orginPizza {
public static void main(String[] args) {
Pizza pizza;
SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();
PizzaStore pizzaStore = new PizzaStore(simplePizzaFactory);
pizza = pizzaStore.orderPizza("cheese");
System.out.println(pizza.getName()+"Pizza准备完毕!");
}
}
/*
* orderPizza通过简单传入类型,然后使用工厂创建比萨
* 即把new新对象的操作放在factory.createPizza(type);中
*/
class PizzaStore{
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory){
this.factory = factory;
}
public Pizza orderPizza(String type){
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
class SimplePizzaFactory{
public Pizza createPizza(String type){
Pizza pizza = null;
if(type.equals("cheese")){
pizza = new CheesePizza("cheese");
}else if(type.equals("greek")){
pizza = new GreekPizza("greek");
}else if(type.equals("pepperoni")){
pizza = new PeppernoiPizza("pepperoni");
}
return pizza;
}
}
abstract class Pizza{
String name;
String dough;
String sauce;
void prepare(){
//姓名、调料、面团之类的准备
System.out.println("准备材料完毕!");
}
void bake(){
System.out.println("bake over!");
}
void cut(){
System.out.println("cut over!");
}
void box(){
System.out.println("box over!");
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDough() {
return dough;
}
public void setDough(String dough) {
this.dough = dough;
}
public String getSauce() {
return sauce;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
}
/*
抽象类先继承,再实例化
*/
class CheesePizza extends Pizza{
private String name;
public CheesePizza(){};
public CheesePizza(String name){
this.name = name;
}
public String getName() {
return name;
}
}
class GreekPizza extends Pizza{
private String name;
public GreekPizza(){};
public GreekPizza(String name){
this.name = name;
}
public String getName() {
return name;
}
}
class PeppernoiPizza extends Pizza{
private String name;
public PeppernoiPizza(){};
public PeppernoiPizza(String name){
this.name = name;
}
public String getName() {
return name;
}
}
输出依旧不变
准备材料完毕!
bake over!
cut over!
box over!
cheesePizza准备完毕!
我们接着往下看加盟店的情况,咳咳咳,可能一些朋友看到这里突然困了,那么我们睡一会再继续看 。
2.2.加盟分厂
如果在此基础上建披萨加盟店,代理不同风格的披萨
PizzaStore chicagoStylePizzaStore = new ChicagoStylePizzaStore();//芝加哥披萨工厂
Pizza pizza = chicagoStylePizzaStore.orderPizza("cheese");//制造披萨
2.2.1. 依赖倒置原则
依赖倒置原则:程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块之间的耦合。
PizzaStore依赖于所有的具体披萨对象,披萨具体实现的任何改变都会影响PizzaStore。每增加一个披萨种类,等于让PizzaStore多了一个依赖。
引入加盟分厂后,高层组件(PizzaStore)和低层组件(这些披萨)都依赖于Pizza抽象。这也是为什么称之依赖倒置原则的原因。
对于创建者类PizzaStore,其继承关系如下
我们希望orderPizza的过程是属于披萨店的一致操作,而createPizza就属于各个店分内的工作了。即将PizzaStore设计为抽象(abstract)方法,使用orderPizza()调用createPizza()。
2.2.2. 产品类Pizza
对于产品类pizza,其继承关系如下
2.2.3.正式开店
纽约风味分店:
(为了便于理解,减少代码量,故veggie/clam/pepperoni种类的披萨类没有创建)
class NYStylePizzaStore extends PizzaStore{
protected Pizza createPizza(String item){
Pizza pizza = null;
if(item.equals("cheese")){
return new NYStyleCheesePizza();
//pizza.setName("New York Style Cheese Pizza");
}else if(item.equals("veggie")){
pizza.setName("New York Style Veggie Pizza");
}else if(item.equals("clam")){
pizza.setName("New York Style Clam Pizza");
}else if(item.equals("pepperoni")){
pizza.setName("New York Style Pepperoni Pizza");
}
return pizza;
}
}
2.2.4.利用披萨工厂方法订购披萨
- Tom和Jack需要获得披萨店的实例.Tom需要一个ChicagoPizzaStore,而Jack需要一个NYPizzaStore
PizzaStore chicagoStylePizzaStore = new ChicagoStylePizzaStore();
- Tom和Jack分别调用orderPizza()方法,并传入他们所喜爱的披萨类型(芝士、素食…)
Pizza pizza = chicagoStylePizzaStore.orderPizza("cheese");
- orderPizza()调用createPizza()创建披萨,其中NYPizzaStore和ChicagoPizzaStore分别实例化对应的披萨.createPizza()将创建好的披萨作为返回值.
pizza = createPizza("cheese");
- orderPizza()像是一道加工程序,并不知道取到的是什么披萨,只是根据提供的"调料",被准备、被烘烤、被切片、被装盒,最后提供给Tom和Jack即返回披萨.
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
具体实现披萨: 继承抽象的Pizza类,实现具体的披萨,然后赋予pizza做法。
/*
抽象类先继承,再实例化
*/
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");
}
}
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");
}
}
生产->定披萨全流程: 首先建立两个不同的店,然后用店调用orderPizza帮用户下单
public class orginPizza {
public static void main(String[] args) {
PizzaStore chicagoStylePizzaStore = new ChicagoStylePizzaStore();
Pizza pizza = chicagoStylePizzaStore.orderPizza("cheese");
System.out.println(pizza.getName()+"准备完毕!");
}
}
2.2.5. 完整代码
我们按照需要将simplePizzaFactory改变为具体的具有不同地域风格的分厂。
public class orginPizza {
public static void main(String[] args) {
//以tom为例,需要一个芝加哥的芝士
PizzaStore chicagoStylePizzaStore = new ChicagoStylePizzaStore();
Pizza pizza = chicagoStylePizzaStore.orderPizza("cheese");
System.out.println(pizza.getName()+"准备完毕!");
}
}
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);//Pizza的子类可以访问该函数
}
//纽约披萨分厂
//这里仅定义了NYStyleCheesePizza();
class NYStylePizzaStore extends PizzaStore{
protected Pizza createPizza(String item){
Pizza pizza = null;
if(item.equals("cheese")){
return new NYStyleCheesePizza();
//pizza.setName("New York Style Cheese Pizza");
}else if(item.equals("veggie")){
pizza.setName("New York Style Veggie Pizza");
}else if(item.equals("clam")){
pizza.setName("New York Style Clam Pizza");
}else if(item.equals("pepperoni")){
pizza.setName("New York Style Pepperoni Pizza");
}
return pizza;
}
}
//芝加哥披萨分厂
class ChicagoStylePizzaStore extends PizzaStore{
protected Pizza createPizza(String item){
Pizza pizza = null;
if(item.equals("cheese")){
return new ChicagoStyleCheesePizza();
//pizza.setName("Chicago Style Cheese Pizza");
}else if(item.equals("veggie")){
pizza.setName("Chicago Style Veggie Pizza");
}else if(item.equals("clam")){
pizza.setName("Chicago Style Clam Pizza");
}else if(item.equals("pepperoni")){
pizza.setName("Chicago Style Pepperoni Pizza");
}
return pizza;
}
}
abstract class Pizza{
String name;
String dough;
String sauce;
void prepare(){
//姓名、调料、面团之类的准备
System.out.println("准备材料完毕!");
}
void bake(){
System.out.println("bake over!");
}
void cut(){
System.out.println("cut over!");
}
void box(){
System.out.println("box over!");
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDough() {
return dough;
}
public void setDough(String dough) {
this.dough = dough;
}
public String getSauce() {
return sauce;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
}
/**
* 披萨子类先继承抽象类Pizza,再实例化
*/
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");
}
}
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");
}
}
**
程序输出
准备材料完毕!
bake over!
Cutting the pizza into square slices
box over!
Chicago Style Deep Dish Cheese Pizza准备完毕!
可以发现其按照自己“独特"的方式切披萨,并按照需要准备好了Chicago Style Deep Dish Cheese Pizza。
接下来才是重头戏!工厂模式粉墨登场~
2.3.原料工厂
2.3.1.依赖型披萨店
如若不使用工厂模式,披萨店的代码会是:
public class DependentPizzaStore{
public Pizza createPizza(String style,Style type){
Pizza pizza = null;
if(style.equals("NY")){//纽约风味
if(type.equals("cheese"))
pizza = new NYStyleCheesePizza();
blabla..
} else if(style.equals("Chicago")){//芝加哥风味
balbla..
}else{
balbla..
}
pizza.prepare();
pizza.bake();
pizza.cut();
..
return pizza;
}
}
2.3.2.原料家族
为了保证加盟店与主店具有相同品质的披萨,避免分店偷工减料增加利润,准备不同的材料运送到各个分店,可是分店距离太远怎么办呢?这往往难以保证每天的食材新鲜。
每个家族工厂都包含了一种面团、一种酱料、一种芝士、以及一种海鲜佐料,但是都各具“家族特色”。
纽约原料工厂:
/**
* 具体的原料工厂必须实现PizzaIngredientFactory接口
* 原料的生成方法
* */
class NYPizzaIngredientFactory implements PizzaIngredientFactory{
@Override
public Dough createDough(){//这里用一种类举例
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return null;
}
@Override
public Cheese createCheese(){
return null;
}
@Override
public Veggies[] createVeggies() {
return new Veggies[0];
}
@Override
public Pepperoni createPepperoni() {
return null;
}
@Override
public Clams createClam() {
return null;
}
}
重做披萨:
现在我们要使用自己的原料工厂来重新制作披萨了
/**
* Pizza类
* 抽象类,子披萨类需要继承它
* */
abstract class Pizza{
String name;
String dough;
String sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
void prepare(){
//姓名、调料、面团之类的准备
System.out.println("准备材料完毕!");
}
void bake(){
System.out.println("bake over!");
}
void cut(){
System.out.println("cut over!");
}
void box(){
System.out.println("box over!");
}
public Veggies[] getVeggies() {
return veggies;
}
public void setVeggies(Veggies[] veggies) {
this.veggies = veggies;
}
public Cheese getCheese() {
return cheese;
}
public void setCheese(Cheese cheese) {
this.cheese = cheese;
}
public Pepperoni getPepperoni() {
return pepperoni;
}
public void setPepperoni(Pepperoni pepperoni) {
this.pepperoni = pepperoni;
}
public Clams getClam() {
return clam;
}
public void setClam(Clams clam) {
this.clam = clam;
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDough() {
return dough;
}
public void setDough(String dough) {
this.dough = dough;
}
public String getSauce() {
return sauce;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
}
从今以后,加盟店必须直接从工厂取得原料,那些偷工减料的日子宣告结束了!之前写过的两个工厂方法,NYCheesePizza和ChicagoCheesePizza类,他们的差别仅仅在于使用区域性的原料,至于披萨的做法都是一样的。所以这里的两个不同的类生产不同风味的披萨是可以解耦的,让原料工厂来处理这种区域差异即可。
/**
* Pizza的子类
* */
class CheesePizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
System.out.println("Preparing" + name);
dough = String.valueOf(ingredientFactory.createDough());//面包片
sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
cheese = ingredientFactory.createCheese();//芝士
}
}
class VeggiePizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public VeggiePizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
System.out.println("Preparing" + name);
dough = String.valueOf(ingredientFactory.createDough());//面包片
sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
cheese = ingredientFactory.createCheese();//芝士
}
}
class ClamPizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
System.out.println("Preparing" + name);
dough = String.valueOf(ingredientFactory.createDough());//面包片
sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
cheese = ingredientFactory.createCheese();//芝士
clam = ingredientFactory.createClam();//蛤蜊
}
}
class PepperoniPizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public PepperoniPizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
System.out.println("Preparing" + name);
dough = String.valueOf(ingredientFactory.createDough());//面包片
sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
cheese = ingredientFactory.createCheese();//芝士
}
}
现在的披萨店:
/**
* 纽约加盟店
**/
class NYPizzaStore extends PizzaStore{
protected Pizza createPizza(String item){
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if(item.equals("cheese")){
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
}else if(item.equals("veggie")){
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Veggie Pizza");
}else if(item.equals("clam")){
pizza = new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
}else if(item.equals("pepperoni")){
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("New York Style Pepperoni Pizza");
}
return pizza;
}
}
对比前一个版本的createPizza()
public class NYPizzaStore extends PizzaStore(){
Pizza createPizza(String item){
if(item.equals("cheese")){
return new NYStyleCheesePizza();
}else if(item.equals("veggie")){
return new NYStyleVeggiePizza();
}else if(item.equals("clam")){
return new NYStyleClamPizza();
}else if(item.equals("pepperoni")){
return new NYStylePepperoniPizza();
}else return null;
}
}
不同点:
原来是选择cheese,然后直接得到了NYStyleCheesePizza。而现在虽然同样是选择cheese,但是根据原料工厂来确定是NYStyleCheesePizza,进一步将原料的选择与披萨的形成抽象化了。
2.3.3.完整代码
public class IngredientFactoryExample {
public static void main(String[] args) {
PizzaStore nyPizzaStore = new NYPizzaStore();
nyPizzaStore.orderPizza("cheese");
}
}
/**
* PizzaStore工厂
* 抽象类,加盟店需要继承它
* orderPizza通过简单传入类型,把new新对象的操作放在createPizza(type);中
*/
public class IngredientFactoryExample {
public static void main(String[] args) {
PizzaStore nyPizzaStore = new NYPizzaStore();
Pizza pizza = nyPizzaStore.orderPizza("cheese");
System.out.println(pizza.name + "准备完毕!");
}
}
/**
* PizzaStore工厂
* 抽象类,加盟店需要继承它
* orderPizza通过简单传入类型,把new新对象的操作放在createPizza(type);中
*/
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);
}
/**
* Pizza类
* 抽象类,子披萨类需要继承它
* */
abstract class Pizza{
String name;
String dough;
String sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
void prepare(){
//姓名、调料、面团之类的准备
System.out.println("准备材料完毕!");
}
void bake(){
System.out.println("bake over!");
}
void cut(){
System.out.println("cut over!");
}
void box(){
System.out.println("box over!");
}
public Veggies[] getVeggies() {
return veggies;
}
public void setVeggies(Veggies[] veggies) {
this.veggies = veggies;
}
public Cheese getCheese() {
return cheese;
}
public void setCheese(Cheese cheese) {
this.cheese = cheese;
}
public Pepperoni getPepperoni() {
return pepperoni;
}
public void setPepperoni(Pepperoni pepperoni) {
this.pepperoni = pepperoni;
}
public Clams getClam() {
return clam;
}
public void setClam(Clams clam) {
this.clam = clam;
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDough() {
return dough;
}
public void setDough(String dough) {
this.dough = dough;
}
public String getSauce() {
return sauce;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
}
/**
* 具体的原料工厂必须实现PizzaIngredientFactory接口
* 原料的生成方法
* */
class NYPizzaIngredientFactory implements PizzaIngredientFactory{
@Override
public Dough createDough(){//这里用一种类举例
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return null;
}
@Override
public Cheese createCheese(){
return null;
}
@Override
public Veggies[] createVeggies() {
return new Veggies[0];
}
@Override
public Pepperoni createPepperoni() {
return null;
}
@Override
public Clams createClam() {
return null;
}
}
/**
* 面团类
**/
class Dough {
}
/**
* 面团的一种子类
* 薄皮面团
**/
class ThinCrustDough extends Dough{
public void ThinCrustDough(){//构造方法
}
}
/**
* Pizza的子类
* */
class CheesePizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
System.out.println("Preparing" + name);
dough = String.valueOf(ingredientFactory.createDough());//面包片
sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
cheese = ingredientFactory.createCheese();//芝士
}
}
class VeggiePizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public VeggiePizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
System.out.println("Preparing" + name);
dough = String.valueOf(ingredientFactory.createDough());//面包片
sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
cheese = ingredientFactory.createCheese();//芝士
}
}
class ClamPizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
System.out.println("Preparing" + name);
dough = String.valueOf(ingredientFactory.createDough());//面包片
sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
cheese = ingredientFactory.createCheese();//芝士
clam = ingredientFactory.createClam();//蛤蜊
}
}
class PepperoniPizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public PepperoniPizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
System.out.println("Preparing" + name);
dough = String.valueOf(ingredientFactory.createDough());//面包片
sauce = String.valueOf(ingredientFactory.createSauce());//大蒜
cheese = ingredientFactory.createCheese();//芝士
}
}
/**
* 纽约加盟店
**/
class NYPizzaStore extends PizzaStore{
protected Pizza createPizza(String item){
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if(item.equals("cheese")){
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
}else if(item.equals("veggie")){
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Veggie Pizza");
}else if(item.equals("clam")){
pizza = new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
}else if(item.equals("pepperoni")){
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("New York Style Pepperoni Pizza");
}
return pizza;
}
}
/**
* 其他原料类
* */
class Sauce {
}
class Cheese {
}
class Veggies{
}
class Pepperoni {
}
class Clams {
}
/**
* Pizza原料工厂接口
* 每个原料类都有一个对应的方法创建该原料
* */
interface PizzaIngredientFactory{
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
输出
PreparingNew York Style Cheese Pizza
bake over!
cut over!
box over!
New York Style Cheese Pizza准备完毕!
这里的工厂使用了抽象类,用于创建相关或依赖对象的家族,而不需要明确指定具体类。使用对象组合。
抽象工厂模式定义了一个接口,所有的具体工厂都必须实现此接口,这个接口包含一组方法用来生产产品。每个具体的工厂都可以生产所有的产品。
看了上述的类图可以发现,与工厂模式不同的是,一旦需要扩展这组产品,就需要更改接口,相应的子类的接口也要改变。此外,抽象工厂模式中的具体工厂会使用到工厂模式。
三、总结与补充
1、将PizzaStore从简单工厂优化到工厂,从而优化(抽象)一个共性:地域风格,例如纽约风格,芝加哥风格,中式风格。
2、产品类Pizza和创建类PizzaStore都抽象化,并根据依赖倒置原则,将顶层PizzaStore和低层具体的Pizza类都设计为依赖产品类。形成抽象工厂(工厂模式之间的区别见5)。
3、原料类抽象化,然后将其子类实例作为pizza子类的参数(即采用构造器方式注入)。
4、总之,将共性抽象化,实现客户与实际对象创建的解耦。
3.1.什么时候使用工厂模式?
为了提高扩展性和维护性,多写些代码是值得的。
1、类本身有很多子类,并且经常会发生变化。创建对象需要大量重复的代码。比如肯德基新品。
2、消费者不关心如何创建对象(产品类)。
3.2.简单工厂模式和工厂模式有什么区别?
简单工厂模式是“一把抓”
//SimplePizzaFactory,创建披萨
public class SimplePizzaFactory{
public Pizza createPizza(String type){
Pizza pizza = null;
//上述代码段
if(type.equals("cheese")){//奶酪
pizza = new CheesePizza("cheese");
}else if(type.equals("greek")){//希腊
pizza = new GreekPizza("greek");
}else if(type.equals("pepperoni")){//香肠
pizza = new PeppernoiPizza("pepperoni");
}else.....
//增加新的产品。。。
}
}
1、负担太重
2、不符合开闭原则
● 工厂方法模式就很好的减轻了工厂类的负担,把某一类/某一种东西交由一个工厂生产;(对应简单工厂的缺点1)。
● 同时增加某一类 ”东西“ 并不需要修改工厂类,只需要添加生产这类 ”东西“ 的工厂即可,使得工厂类符合开放-封闭原则。
3.3.工厂模式是否遵守了开闭原则?
开闭原则: 对扩展开放,对修改关闭
(1)增加产品族:对于增加新的产品族,抽象工厂模式很好地支持了“开闭原则”,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。
(2)增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了“开闭原则”。
3.4.抽象工厂、工厂、简单工厂的区别
工厂与简单工厂: 简单工厂是工厂的一种特例,可以简单理解简单工厂就是一个超级工厂,包罗万象,产品之间无关联。而工厂就是把这个超级工厂给抽象化,并划分成多个子工厂。
抽象工厂: 抽象工厂的目的是减少工厂数量,但是具备一定的条件,即这些工厂需要具备至少两个及以上的共性。拿披萨为例,即可以分多个维度去分类,如地域、口味、原料三个维度。按照地域可以分为纽约、芝加哥等等。按照口味可以分为芝士、巧克力等等。按照原料可以分为葱、面包等等。将至少两个以上的这种共性抽象化,即抽象工厂。
四、参考文献
1.抽象工厂模式与开闭原则_iteye_7839的博客-CSDN博客
2.工厂模式和抽象工厂的区别是什么? - Single_Yam - 博客园 (cnblogs.com)
最后,设计模式的设计并没有完美的,一个项目的开发,也是结合各种模式的优缺点来设计,看到其优缺点灵活使用即可。
OVER~
我讲明白了吗?欢迎评论交流~
以上是对工厂模式学习过程的总结,如果对您有帮助,记得留个赞哦~