先编一个这么久不写的理由

上周我终于鼓起勇气翻开了headfirst设计模式这本书,看看自己下一个设计模式要写个啥,然后,我终于知道我为啥这么久都没写设计模式了,headfirst的这个抽象工厂模式,额,我看了好几次,都不太理解。

在我的印象中,简单工厂,工厂方法,抽象工厂,这三个东西应该是层层递进的,然后我带着这个思路去看,emmmm,真的没看懂,还好最近又补了一遍《大话设计模式》,揣着刚刚温习了的新知识,然后又上了headfirst这条船,我感觉我这次应该是看懂了。

所以不写并不是因为忙,也不是因为懒,什么上分和吃鸡,我根本都没有听说过,和一个996的码农说这些,表示很扎心。

看完了工厂模式以后,发现后面居然是单例模式,兄弟,你是认真的吗?(泪流满面)

抽象工厂举例分析

首先,我去看了一下这本书配套的源代码,嗯,抽象工厂的类,感觉太多太多了,带上测试类一共是35个,这要是贴出来,可以水很大的篇幅了,但是我是那种人吗?当然不是!

碰到这种情况当然是直接给地址,有需要的小伙伴可以自己去看

github地址:https://github.com/bethrobson/Head-First-Design-Patterns

工厂模式递进体系分析

先捋一捋书中描述的抽象工厂是个什么意思,要说清楚这个,就必须先说一下它整个工厂模式的叙述的递进关系,具体如下:

1,先拿一个贼简单的创建Pizza的简单工厂类PizzaStore,来忽悠我,这章很简单,来学学吧,这章源代码只有8个类

2,兴冲冲的看完了第一部分,当然是一鼓作气的看第二部分,第二部分总结起来大概是讲这么一个事情:

  1)我们公司在纽约的那个旗舰店(PizzaStore)生意不错,现在我们要开一个分店,名字叫芝加哥披萨店(ChicagoPizzaStore)

  2)分店开了以后,原来的先进经验不能丢啊,所以PizzaStore被抽象出来了,搞成了一个抽象类,作为基础技术储备

  3)PizzaStore变成了公司的基础部门,专门指导披萨制作的流程

  4)旗舰店没办法啊,一方面自己的名字被占用了,一方面规范管理的风也吹来了,就改名字叫纽约披萨店(NYPizzaStore),旗下的所有披萨也顺势把名字也改了

  5)新开起来的芝加哥披萨店,倚靠了公司的技术实力,copy了一份旗舰店的菜单,但是也要照顾本地人的口味啊,所以就因地制宜,开发了自己的产品

  整个事情就是这样,涉及到的类有:pizza抽象类(1个),PizzaStore抽象类(1个),实体披萨店(2个),实体店的各类Pizza(8个),测试类(1个)

  总的来说,这一部分的递进关系很棒,也能很好的体现,简单工厂和工厂方法最大的不同,工厂方法可以对工厂类做到:开闭原则

3,工厂方法扯完了,就来看一下,抽象工厂嘛,这一波操作我当时着实没有看懂,就一直搁置了,为什么当时没看懂呢?

对于正常的抽象工厂的讲解套路来说应该是这个样子的:新增加一个产品线(抽象类,实现类),重新规划一下Factory的接口和实现类(Factory里新加一个接口,实现类新增实现)

它没有这样搞,它直接根据披萨原料,重新抽象了一套抽象工厂模式的体系出来,不得不说,这个比刚才说的那个新增产品线的例子漂亮太多了,原因有以下几点:

  1)直接新增一个产品线的这种操作,虽然更容易理解,但是会给人一个误导:我在原来Factory新增接口的这个操作,是符合设计模式,符合抽象工厂模式的

  2)抽象工厂的缺点是什么?缺点就是,Factory的接口,在实际使用的时候,几乎是无法新增产品的,修改太多了。所以它选择了使用原料这套新体系来讲解,更加符合实际

当然,它的例子也不是没有缺点,个人感觉它的缺点有以下几点:

  1)产生了类太多了,35个(上面有说过),对新手不友好,看到这个量级,稍微往后一翻又是一个单例模式,想着这个东西又不怎么能用上,有求生欲望的,都不会在放弃的边缘疯狂试探……

  2)对它本身的工厂方法模式的体系(PizzaStore体系),也有很大量的修改,集中体现在各类Pizza实现类的缩减(取消了按店铺名称来创建的各类披萨,转而使用了简单工厂模式里面的名字),Pizza的方法实现也有很多修改,主要是为了支持原料体系,当然,虽然产生了很多的修改,但是对外部提供的接口是没有影响的,换句话说,虽然实现有了翻天覆地的变化,但是顾客还是无感知的,这个从测试代码就能看出来:

工厂方法模式测试类:

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"); pizza = nyStore.orderPizza("clam");
System.out.println("Ethan ordered a " + pizza.getName() + "\n"); pizza = chicagoStore.orderPizza("clam");
System.out.println("Joel ordered a " + pizza.getName() + "\n"); pizza = nyStore.orderPizza("pepperoni");
System.out.println("Ethan ordered a " + pizza.getName() + "\n"); pizza = chicagoStore.orderPizza("pepperoni");
System.out.println("Joel ordered a " + pizza.getName() + "\n"); pizza = nyStore.orderPizza("veggie");
System.out.println("Ethan ordered a " + pizza.getName() + "\n"); pizza = chicagoStore.orderPizza("veggie");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
}
}

抽象工厂测试类:

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 + "\n"); pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza + "\n"); pizza = nyStore.orderPizza("clam");
System.out.println("Ethan ordered a " + pizza + "\n"); pizza = chicagoStore.orderPizza("clam");
System.out.println("Joel ordered a " + pizza + "\n"); pizza = nyStore.orderPizza("pepperoni");
System.out.println("Ethan ordered a " + pizza + "\n"); pizza = chicagoStore.orderPizza("pepperoni");
System.out.println("Joel ordered a " + pizza + "\n"); pizza = nyStore.orderPizza("veggie");
System.out.println("Ethan ordered a " + pizza + "\n"); pizza = chicagoStore.orderPizza("veggie");
System.out.println("Joel ordered a " + pizza + "\n");
}
}

是一个非常赞的地方

抽象工厂实现过程

首先,我们从原料的工厂类入手:

public interface PizzaIngredientFactory {

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

一共有6种原料可以创建,这个也是它源代码类多的原因之一,由于大多数代码都是相似的,所以这里也就不一一的列举了只列举流程相关的实现

先看酱油(Sauce)相关的接口和实现:

public interface Sauce {
String toString();
}

PlumTomatoSauce:

public class PlumTomatoSauce implements Sauce {
public String toString() {
return "Tomato sauce with plum tomatoes";
}
}

MarinaraSauce:

public class MarinaraSauce implements Sauce {
public String toString() {
return "Marinara Sauce";
}
}

然后看看面团的相关接口和实现:

public interface Dough {
String toString();
}

ThickCrustDough:

public class ThickCrustDough implements Dough {
public String toString() {
return "ThickCrust style extra thick crust dough";
}
}

ThinCrustDough:

public class ThinCrustDough implements Dough {
public String toString() {
return "Thin Crust Dough";
}
}

以上,是抽象工厂的基础:产品族的工厂类,产品接口(或者是抽象类),产品的具体实现类请忽略它只是为了方便理解放到一起的

列举了这个,再来看看具体的原料工厂:

ChicagoPizzaIngredientFactory:

public class ChicagoPizzaIngredientFactory
implements PizzaIngredientFactory
{ //我是面团,我是这里
public Dough createDough() {
return new ThickCrustDough();
} //我是酱油,我在这里
public Sauce createSauce() {
return new PlumTomatoSauce();
} public Cheese createCheese() {
return new MozzarellaCheese();
} public Veggies[] createVeggies() {
Veggies veggies[] = { new BlackOlives(),
new Spinach(),
new Eggplant() };
return veggies;
} public Pepperoni createPepperoni() {
return new SlicedPepperoni();
} public Clams createClam() {
return new FrozenClams();
}
}

NYPizzaIngredientFactory:

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {

    //我是面团,我在这里
public Dough createDough() {
return new ThinCrustDough();
} //我是酱油,我在这里
public Sauce createSauce() {
return new MarinaraSauce();
} public Cheese createCheese() {
return new ReggianoCheese();
} public Veggies[] createVeggies() {
Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
return veggies;
} public Pepperoni createPepperoni() {
return new SlicedPepperoni();
} public Clams createClam() {
return new FreshClams();
}
}

实现也是很简单的,这里为了不占篇幅就隐藏了,有需要的自己点开看,接下来看一个这个原料体系的建立,需要修改的体现:

1,各类Pizza的实现类,需要持有PizzaIngredientFactory对象,并且prepare方法会有修改

public class ClamPizza extends Pizza {
PizzaIngredientFactory ingredientFactory; public ClamPizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
} void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
clam = ingredientFactory.createClam();
}
}

2,具体的pizza工厂的修改:

public class ChicagoPizzaStore extends PizzaStore {

    protected Pizza createPizza(String item) {
Pizza pizza = null;
//创建各自的原料工厂
PizzaIngredientFactory ingredientFactory =
new ChicagoPizzaIngredientFactory(); if (item.equals("cheese")) {
//创建具体pizza的时候传入原料工厂
pizza = new CheesePizza(ingredientFactory);
pizza.setName("Chicago Style Cheese Pizza"); } else if (item.equals("veggie")) { pizza = new VeggiePizza(ingredientFactory);
pizza.setName("Chicago Style Veggie Pizza"); } else if (item.equals("clam")) { pizza = new ClamPizza(ingredientFactory);
pizza.setName("Chicago Style Clam Pizza"); } else if (item.equals("pepperoni")) { pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("Chicago Style Pepperoni Pizza"); }
return pizza;
}
}

以上就是抽象工厂类的实现套路,以及在head first中,对原工厂方法模式具体影响的叙述,贴代码是不可能贴代码的,这辈子都不可能贴代码的

headfirst设计模式(5)—工厂模式体系分析及抽象工厂模式的更多相关文章

  1. 设计模式可复用面向对象软件设计基础之对象创建型模式—ABSTRACT FACTORY( 抽象工厂)

    意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 适用性 在以下情况可以使用 Abstract Factory模式 • 一个系统要独立于它的产品的创建.组合和表示时. • 一 ...

  2. Java 工厂模式(一)— 抽象工厂(Abstract Factory)模式

    一.抽象工厂模式介绍: 1.什么是抽象工厂模式: 抽象工厂模式是所有形态的工厂模式中最为抽象和最具有一般性的一种形态,抽象工厂模式向客户端提供一个接口,使得客户端在不知道具体产品的情类型的情况下,创建 ...

  3. php设计模式课程---3、为什么会有抽象工厂方法

    php设计模式课程---3.为什么会有抽象工厂方法 一.总结 一句话总结: 解决简单工厂方法增加新选择时无法满足面向对象编程中的开闭原则问题 1.什么是面向对象编程中的开闭原则? 应该对类的增加开放, ...

  4. 系统架构-设计模式(适配器、观察者、代理、抽象工厂等)及架构模式(C/S、B/S、分布式、SOA、SaaS)(干货)

    博客园首页是需要分享干货的地方,今天早上写的<HRMS(人力资源管理系统)-从单机应用到SaaS应用-系统介绍>内容下架了,所以我就按照相关规定,只分享干货,我把之前写完的内容整理发布上来 ...

  5. 设计模式(一): abstract factory抽象工厂模式 -- 创建型模式

    1.定义 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 2.适用场景 1.一个系统要独立于它的产品创建.组合和表示. 2.一个系统要由多个产品系列中的一个来配置. 3.当你要 ...

  6. Android设计模式(十二)--抽象工厂模式

    问题: 抽象工厂模式,是一个,狠恶心的模式,那么这个模式在Android有没实用到过呢? 1.定义: 抽象工厂模式:为创建一组相关或者是相互依赖的对象提供一个接口,而不须要指定他们的详细类. 2.使用 ...

  7. 设计模式C++学习笔记之七(AbstractFactory抽象工厂模式)

      抽象工厂,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类.对于工厂方法来说,抽象工厂可实现一系列产品的生产,抽象工厂更注重产品的组合. 看代码: 7.1.解释 main(),女 ...

  8. 设计模式之美:Abstract Factory(抽象工厂)

    索引 别名 意图 结构 参与者 适用性 缺点 效果 相关模式 命名约定 实现 实现方式(一):使用 Factory Method 来实现 Abstract Factory. 实现方式(二):使用 Pr ...

  9. 设计模式系列 1——StaticFactory(静态工厂),AbstractFactory(抽象工厂)

    本文出自 代码大湿 代码大湿 本系列持续更新,敬请关注. 1 静态工厂 静态工厂介绍: 静态工厂模式可以实现接口封装隔离的原则.在客户端只知接口而不知实现的时候可以使用静态工厂模式. 源码请点击我 角 ...

随机推荐

  1. 【Java进阶】并发编程

    PS:整理自极客时间<Java并发编程> 1. 概述 三种性质 可见性:一个线程对共享变量的修改,另一个线程能立刻看到.缓存可导致可见性问题. 原子性:一个或多个CPU执行操作不被中断.线 ...

  2. 深入学习Redis(3):主从复制

    前言 在前面的两篇文章中,分别介绍了Redis的内存模型和Redis的持久化. 在Redis的持久化中曾提到,Redis高可用的方案包括持久化.主从复制(及读写分离).哨兵和集群.其中持久化侧重解决的 ...

  3. 如何使用FluentMigrator进行数据库迁移

    标题:如何使用FluentMigrator进行数据库迁移 地址:https://www.cnblogs.com/lwqlun/p/10649949.html 作者: Lamond Lu FluentM ...

  4. 打造自己的Android常用知识体系

    前言 Android常用知识体系是什么鬼?所谓常用知识体系,就是指对项目中重复使用率较高的功能点进行梳理.注意哦,不是Android知识体系. 古语道:学而不思则罔,思而不学则殆.如果将做项目类比为“ ...

  5. mvc、mvp和mvvm

    一.MVC 设计图: 可能由于MVP.MVVM的兴起,MVC在android中的应用变得越来越少了,但MVC是基础,理解好MVC才能更好的理解MVP,MVVM.因为后两种都是基于MVC发展而来的. 1 ...

  6. SAP MM已经转成PO的采购申请Item依旧可以被删除?

    SAP MM已经转成PO的采购申请Item依旧可以被删除? 笔者测试发现,我们可以删除已产生PO的PR item, 系统只是给一个警告信息,不阻止保存. Purchase orders already ...

  7. JavaScript函数定义 ,参数调用

    一.JavaScript函数函数: 函数就是一种封装,由事件驱动的或者当它被调用时执行的可重复使用的代码块.定义函数:function 函数名(){函数体;}数不会自动执行,需要被调用才可以执行函数名 ...

  8. SQL优化--inner、left join替换in、not in、except

    新系统上线,用户基数16万,各种查询timeout.打开砂锅问到底,直接看sql语句吧,都是泪呀,一大堆in\not in\except.这里总结一下,怎么替换掉in\not in\except. 1 ...

  9. Android JS桥交互("Uncaught ReferenceError: xxx is not defined or xxx has no method")

    网上android和js交互的代码有不少,也很容易搜到.最近在做的项目需要用到js桥,遇到了一些问题,记录下来,希望以后遇到能马上解决掉. 一开始我找的demo是从这个:http://blog.csd ...

  10. 深入理解 call,apply 和 bind

    在JavaScript 中,call.apply 和 bind 是 Function 对象自带的三个方法,这三个方法的主要作用是改变函数中的 this 指向,从而可以达到`接花移木`的效果.本文将对这 ...