Head First设计模式——简单工厂、工厂、抽象工厂
前言:按照惯例我以Head First设计模式的工厂模式例子开始编码学习。并由简单工厂,工厂模式,抽象工厂模式依次演变,归纳他们的相同与不同。
话说Head First认为简单工厂并不是设计模式,而是一种编程习惯,但并不妨碍我们使用它,接下来我们对工厂模式一探究竟。
1、披萨店例子
首先我们要开一个披萨店,对于业务不复杂的情况下我们可以快速的开发出一个披萨店以及订购披萨的逻辑
public Pizza OrderPizza() {
Pizza pizza = new Pizza(); pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
} public class Pizza {
//准备
public void Prepare() { }
//烘烤
public void Bake() { }
//切片
public void Cut() { }
//装盒
public void Box() { }
}
如果我们有更多的披萨种类可能需要将Pizza定义成抽象类 在订单里面根据订购的披萨种类返回不同的披萨,我们对披萨进行抽象并改造Order。
public class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza=null;
if (type == "cheese")
{
pizza = new CheesePizza();
}
else if (type == "viggie") {
pizza = new VeggiePizza();
}
//else if ......
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
} public abstract class Pizza
{
//准备
public void Prepare() { }
//烘烤
public void Bake() { }
//切片
public void Cut() { }
//装盒
public void Box() { }
} //奶酪披萨
public class CheesePizza : Pizza
{
}
//素食披萨
public class VeggiePizza : Pizza
{
}
到这里我们可能想到了,如果增加披萨种类或者移除披萨那么我们将对披萨店进行修改。
设计原则对扩展开放,对修改关闭。我们需要将创建披萨的变化封装起来。对此弄出来一个专门创建披萨的“工厂“类。
并采用静态,这样就不需要实例化对象,也遵循了不对实现编程原则。
public class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza = SimplePizzaFactory.CreatePizza(type); pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
} public static class SimplePizzaFactory {
public static Pizza CreatePizza(string type) {
Pizza pizza = null;
if (type == "cheese")
{
pizza = new CheesePizza();
}
else if (type == "viggie")
{
pizza = new VeggiePizza();
}
return pizza;
}
}
这样将创建披萨简单的封装起来即是简单工厂(静态工厂),简单工厂也可以不用静态类,但简单工厂并不是一种专门的设计模式(有时候可能会混淆,认为这即是”工厂模式“),更像是我们平时编程都会做的一种习惯。我们将改动封装在一个局部当有变化的时候只需要修改这个工厂类。
2、更多的披萨店
现在我们要开更多的披萨店,例如美国风格披萨店(USSytlePizzaStore)、中国风格披萨店(CHNSytlePizzaStore)。
我们可以采用简单工厂模式,创建两个不同风格的披萨工厂,然后创建两个不同风格的披萨店,不同风格的披萨店使用对应的披萨工厂来获取。
但是我们此时的变化点是披萨店。我们希望披萨店的结构或者流程是按照一定规则的,只是不同风格的披萨。此时我们有更好的解决办法:工厂模式。
接下来我们看如何实现
public abstract class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza= CreatePizza(type); pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
} public abstract Pizza CreatePizza(string type);
} public class USSytlePizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
Pizza pizza = null;
if (type == "cheese")
{
pizza = new USStyleCheesePizza();
}
else if (type == "viggie")
{
pizza = new USStyleVeggiePizza();
}
return pizza;
}
} public class CHNSytlePizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
Pizza pizza = null;
if (type == "cheese")
{
pizza = new CHNStyleCheesePizza();
}
else if (type == "viggie")
{
pizza = new CHNStyleVeggiePizza();
}
return pizza;
}
} //US奶酪披萨
public class USStyleCheesePizza : Pizza
{
}
//US素食披萨
public class USStyleVeggiePizza : Pizza
{
} //CHN奶酪披萨
public class CHNStyleCheesePizza : Pizza
{
}
//CHN素食披萨
public class CHNStyleVeggiePizza : Pizza
{
}
由实现我们可以看到我们将PizzaStore修改成抽象类,不同的披萨店继承抽象类返回自己不同风格的披萨。
这样设计后当增加产品,我们也只是在具体的子类披萨店中修改其中的披萨创建,不会影响披萨店本身流程和其他披萨店的实现。
工厂方法模式:定义了一个创建对象的接口,由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。
工厂方法与简单工厂的区别:工厂方法的子类看起来很像简单工厂。简单工厂把全部的事情在一个地方处理完成,而工厂方法却是创建一个框架,让子类决定如何实现。
3、披萨的不同原料
不同风格的披萨店有不同风格的披萨,而这些披萨的不同风格是来自不同原料造成,所以不同风格的披萨变化的部分是材料。
我们先建造原料和原料工厂,以中国披萨原料工厂为例
//披萨原料工厂接口
public interface PizzaIngredientFactory {
public Veggie CreateVeggie();
public Cheese CreateCheese();
}
//具体工厂实现
public class CNHPizzaIngredientFactory : PizzaIngredientFactory
{
public Cheese CreateCheese()
{
return new CHNCheese();
} public Veggie CreateVeggie()
{
return new CHNVeggie();
}
} public abstract class Veggie
{
}
public class USVeggie : Veggie {
}
public class CHNVeggie : Veggie {
} public abstract class Cheese
{
}
public class USCheese : Cheese
{
}
public class CHNCheese : Cheese
{
}
然后重做Pizza
public abstract class Pizza
{
public String Name;
Veggie veggie;
Cheese cheese;
//准备
public abstract void Prepare();
//烘烤
public void Bake() { }
//切片
public void Cut() { }
//装盒
public void Box() { }
}
加入了原料的抽象 Veggie 和 Cheese,同时我们让Prepare变成抽象方法,让他的具体子类决定用什么材制造不同风格的披萨。接着我们重做子类,以CheesePizza为例
//奶酪披萨
public class CheesePizza : Pizza
{
PizzaIngredientFactory IngredientFactory;
public CheesePizza(PizzaIngredientFactory IngredientFactory) {
this.IngredientFactory = IngredientFactory;
}
public override void Prepare()
{
IngredientFactory.CreateCheese();
}
}
修改中国披萨店
public class CHNSytlePizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
Pizza pizza = null;
//创建中国原材料工厂
CNHPizzaIngredientFactory ingredientFactory = new CNHPizzaIngredientFactory();
if (type == "cheese")
{
pizza = new CheesePizza(ingredientFactory);
}
else if (type == "viggie")
{
pizza = new VeggiePizza(ingredientFactory);
}
return pizza;
}
}
通过这一系列的改造我们引入了新类型的工厂,也就是所谓的抽象工厂,抽象工厂用来创造原料。
利用抽象工厂我们代码将从实际工厂解耦,这样如果我们的工厂需要扩展那么我们则可在子类中进行修改扩展。
工厂方法与抽象工厂的异同优缺点
相同:都是用来创建对象。
不同:工厂方法使用的是继承,抽象工厂使用的是组合。
优点:工厂方法只负责从具体类型中解耦,抽象工厂适合将一群相关的产品集合起来。
缺点:抽象工厂扩展接口需要修改每个子类。
Head First设计模式——简单工厂、工厂、抽象工厂的更多相关文章
- Java设计模式之-----工厂模式(简单工厂,抽象工厂)
一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类:1)简单工厂模式(Simple Factor ...
- 设计模式--简单工厂VS工厂VS抽象工厂
前几天我一直在准备大学毕业生,始终绑起来,如今,终于有时间去学习设计模式.我们研究今天的话题是植物三口之家的设计模式的控制--简单工厂VS工厂VS抽象工厂. 经过细心推敲,我们不难得出:工厂模式是简单 ...
- Java设计模式(三) 抽象工厂模式
原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...
- PHP设计模式(三)抽象工厂模式(Abstract Factory)
一.什么是抽象工厂模式 抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足以下条件: 系统中有多个产品族,而系统一次只可能消费其中一族产品. 同 ...
- Java设计模式学习笔记(四) 抽象工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...
- <十一>读<<大话设计模式>>之抽象工厂模式
学习设计模式有一段时间了,对设计模式有一个体会,就是没那么难.就是设计程序遵循一些原则,让代码可复用,在改动的时候不用涉及太多的类,扩展方便.抽象工厂模式名字听起来抽象.但理解起来一点也不抽象,用语言 ...
- Java的设计模式(4)--抽象工厂模式
提供一个创建一系列或相互依赖对象的接口,而无须指定他们具体的类.例如某些系统可能需要为用户提供一系列相关对象,但系统不希望用户直接使用new运算符实例化这些对象,而是应当由系统来控制这些对象的创建,否 ...
- 详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂) v阅读目录
1楼留头头大神:http://www.cnblogs.com/toutou/p/4899388.html v阅读目录 v写在前面 v简单工厂模式 v工厂方法模式 v抽象工厂模式 v博客总结 v博客 ...
- Head First 设计模式 --4 工厂模式 抽象工厂模式
(用到了依赖倒置原则) 我们写的代码中,有的时候可能会出现根据外面给定的不同的参数在方法中根据参数实例化不同的实例,就是会根据不同的参数会new出不同的实例.如果这么写了,这段代码会非常的脆弱,一旦出 ...
随机推荐
- jQuery常用方法(六)-jQuery 工具
JQuery Utilities 方法说明 jQuery.browser .msie 表示ie jQuery.browser.version 读取用户浏览器的版本信息 jQuery.boxModel ...
- ThinkPHP5 支付宝 电脑与手机支付扩展库
ThinkPHP5 电脑与手机支付扩展库(2017年9月18日) 使用说明 在默认配置情况下,将文件夹拷贝到根目录即可, 其中extend目录为支付扩展目录, application\extra\al ...
- Kafka 异步消息也会阻塞?记一次 Dubbo 频繁超时排查过程
线上某服务 A 调用服务 B 接口完成一次交易,一次晚上的生产变更之后,系统监控发现服务 B 接口频繁超时,后续甚至返回线程池耗尽错误 Thread pool is EXHAUSTED.因为服务 B ...
- Java 学习笔记之 父子类Synchronized
父子类Synchronized: 我们通过一个例子来验证下,父类和子类的Synchronized方法被同时调用,是否是同步的. public class FatherClass { synchroni ...
- Rust入坑指南:核心概念
如果说前面的坑我们一直在用小铲子挖的话,那么今天的坑就是用挖掘机挖的. 今天要介绍的是Rust的一个核心概念:Ownership.全文将分为什么是Ownership以及Ownership的传递类型两部 ...
- Cocos Creator一步一步实现重力球游戏
『 游戏玩法 』 通过手机陀螺仪,调整手机,让球从上一层的间隔中落到下一层,楼层会不断上涨,如果球碰到上方或者下方的火焰,游戏结束. 『 游戏预览 』 『 开发工具 』 1. CocosCreat ...
- B-经济学-基尼指数
目录 基尼指数 一.基尼指数简介 更新.更全的<机器学习>的更新网站,更有python.go.数据结构与算法.爬虫.人工智能教学等着你:https://www.cnblogs.com/ni ...
- 纯C语言写的按键驱动,将按键逻辑与按键处理事件分离~
button drive 杰杰自己写的一个按键驱动,支持单双击.连按.长按:采用回调处理按键事件(自定义消抖时间),使用只需3步,创建按键,按键事件与回调处理函数链接映射,周期检查按键. 源码地址:h ...
- Python web编程 初识TCP UDP
Python网络编程之初识TCP,UDP 这篇文章是读了<Python核心编程>第三版(Core Python Applications)的第二章网络编程后的自我总结. 如果有不到位或者错 ...
- 本地向服务器上传文件的方式-FTP工具上传
笔者负责的一个研究生会的项目,向服务器端传项目代码,用到了FTP工具,这里总结下: FTP方式的步骤: 1,服务器端配置好FTP,(若没有,可网上下载一个服务器端安装的FTP).停止服务后,可以配置账 ...