工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
前言
假设我的朋友Tom有一个披萨店,Tom是镇上最有名的披萨师傅,原因就是因为他作出披萨火候掌握很好,他找到我让我为他做一个点披萨的系统,他说他就做一种披萨,于是我就爽快答应了,于是写出了如下代码。
Pizza orderPizza() {
Pizza pizza = new Pizza();
//准备材料
pizza.prepare();
//烘烤
pizza.bake();
//切
pizza.cut();
//装盒
pizza.box();
return pizza;
}
传统模式
通过这样简单的代码就可以实现点披萨功能。
突然,有一天,对面开了一家披萨店,生意十分火爆,原因就是他们那里有各种各样的披萨。
所以Tom又找到了我,让我在为他的点餐系统中加一些其他种类披萨的代码。
Pizza orderPizza(String type) {
Pizza pizza;
if(type.equals("chess"){
pizza = new ChessPizza();
}else if(type.equals("greek"){
pizza = new GreekPizza();
}else if(type.equals("apple"){
pizza = new ApplePizza();
}
....
//准备材料
pizza.prepare();
//烘烤
pizza.bake();
//切
pizza.cut();
//装盒
pizza.box();
return pizza;
}
哒哒哒哒,大工告成。
对应的类图
简单工厂模式
后来,我们镇里成了闻名世界的披萨小镇,越来越多的披萨店来这里抢生意,越来越多种类的披萨横空出世。
所以后来Tom几乎每周都来找我改系统,学过简单设计模式的我就想到了简单工厂设计模式。
于是,我将经常修改的代码抽取并封装成一个类,交SimpleFactory.
于是代码变成了这样
public class OrderPizza {
public OrderPizza(SimpleFactory factory){
setFactory(factory);
}
SimpleFactory factory = null;
public void setFactory(SimpleFactory simpleFactory){
String orderType = "";//用户输入的
this.factory = simpleFactory;
do{
orderType = getType();
Pizza pizza = factory.createPizza(orderType);
if (pizza != null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("订购Pizza失败!");
break;
}
}while (true);
}
//写一个方法 可以获取客户希望订购的pizza
private String getType() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请在下面输入你要购买的Pizza");
String pizza = reader.readLine();
return pizza;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
SimpleFactory类,将原来经常修改的代码抽取了出来。
public class SimpleFactory {
public static Pizza createPizza(String pizzaType){
Pizza pizza = null;
System.out.println("使用了简单工厂模式");
if (pizzaType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName("greek");
} else if (pizzaType.equals("chess")) {
pizza = new ChessPizza();
pizza.setName("chess");
} else if (pizzaType.equals("pepper")) {
//新增PepperPizza的时候 修改了源代码 违反了ocp原则 如果新增10000个?
//那就很麻烦了
pizza = new PepperPizza();
pizza.setName("pepper");
}
return pizza;
}
}
简单工厂的类图
对比传统模式和简单工厂模式的类图可以看出来,在OrderPizza和Pizza中间又加了一层,原来是OrderPizza依赖Pizza,后来让SampleFactory依赖Pizza。
通过封装SimpleFactory这个类,我们将OrderPizza和Pizza进行了解耦合。
工厂方法模式
Tom又找到了我,说他那里又来了好多披萨店,于是他去了世界各地区学习考察各个地方的披萨风格。
Tom说他已经掌握了世界各地的披萨做法,让我继续为他更改一下系统。
于是,我想到了工厂方法模式。
类图是这样
左边的具体实现应是LDFactory.
AbstractFactory类
public abstract class AbstractFactory {
//具体实现在子类,应用到了多态的特性
abstract Pizza createPizza(String orderType);
public AbstractFactory(){
String orderType = "";//用户输入的
Pizza pizza = null;
do{
orderType = getType();
//创建pizza延迟到子类
pizza = createPizza(orderType);
if (pizza == null){
break;
}
//输出制pizza的流程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.bake();
}while (true);
}
//写一个方法 可以获取客户希望订购的pizza
private String getType() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请在下面输入你要购买的Pizza");
String pizza = reader.readLine();
return pizza;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
BJFactory
public class BJFactory extends AbstractFactory {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("chess")){
pizza = new BJChessPizza();
}else if (orderType.equals("pepper")){
pizza = new BJPepperPizza();
}
return pizza;
}
}
LDFactory
public class LDFactory extends AbstractFactory {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("chess")){
pizza = new LDChessPizza();
}else if (orderType.equals("pepper")){
pizza = new LDPepperPizza();
}
return pizza;
}
}
Pizza
public abstract class Pizza {
protected String name;
public abstract void prepare();
//烤
public void bake(){
System.out.println(name+"baking;");
}
//切
public void cut(){
System.out.println(name+"cutting;");
}
//装盒打包
public void box(){
System.out.println(name+"boxing");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
LDChessPizza
public class LDChessPizza extends Pizza {
@Override
public void prepare() {
setName("伦敦奶酪披萨");
System.out.println("准备伦敦奶酪pizza的原材料.....");
}
}
BJPepperPizza
public class BJPepperPizza extends Pizza{
@Override
public void prepare() {
setName("北京胡椒披萨");
System.out.println("准备北京胡椒pizza的原材料.....");
}
}
工厂方法将对象的实例化推迟到了子类,怎么理解呢?
之前的SimpleFactory在createPizza中直接就new出来了,但是在工厂方法中,我们将createPizza这个动作推迟到了AbstractFactory的子类(XXFactory)中才完成.
原来是由一个对象(SimpleFactory)负责所有具体类的实例化,现在实例化Pizza的责任被移到一个方法中,此方法就如同一个工厂,所以我个人更喜欢称它为方法工厂。
好:简单工厂模式OrderPizza依赖SimpleFactory,工厂方法模式OrderPizza依赖AbstractFactory,所以我们更倾向于后者,我们编程时要尽可能的依赖抽象,这样的话后期的拓展可维护性就会很好,比如我们后期要拓展一个莫斯科披萨,我们就直接编写莫斯科披萨类就好,让他继承AbstractFactory类,实现他自己的功能,这样完全不用修改原来的代码,很好的遵守了OCP原则。但是我们如果还是继续使用简单工厂模式的话,要加入莫斯科chess披萨,我们就要修改SimpleFactory,违反了OCP原则,也没有遵守依赖倒转原则。不好:但是工厂方法模式也有它的缺点,如果后期我们要新增北京其他口味,和伦敦其他口味的披萨的话,我们就必须修改原来的代码,也是违反了对修改关闭的原则。官方点说就是:我们增加新的产品族没毛病,但是如果要拓展已有的产品族的话,会违反OCP原则。
工厂方法模式定义
定义了一个创建对象的接口,但由子类绝对要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
抽象工厂模式
后来Tom又找到了我,说是他以后打败他们,重回巅峰之位,它的想法是这样的,他在做披萨的同时也会添加各中其他的佐料,比如各种各样的酱,各种各样的薄饼,蔬菜…于是我打算重构系统。
我学习了抽象工厂模式之后,觉得之前的工厂方法模式不够抽象,他仅仅是抽象了一个方法,而这次我要把系统重构一下。
类图如下
抽象工厂模式定义:
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
AbstractFactory接口
public interface AbstractFactory {
Pizza createPizza(String orderType);
···········
//创建酱的方法
········
//创建蔬菜的方法
········
}
BJFactory类
public class BJFactory implements AbstractFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("~~~使用的是抽象工厂模式~~~");
Pizza pizza = null;
if (orderType.equals("chess")){
pizza = new BJChessPizza();
}else if (orderType.equals("pepper")){
pizza = new BJPepperPizza();
}
return pizza;
}
//实现其他佐料方法
}
LDFactory类
public class LDFactory implements AbstractFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("~~~使用的是抽象工厂模式~~~");
Pizza pizza = null;
if (orderType.equals("chess")){
pizza = new LDChessPizza();
}else if (orderType.equals("pepper")){
pizza = new LDPepperPizza();
}
return pizza;
}
//实现其他佐料的方法
}
OrderPizza类
public class OrderPizza {
//抽象工厂
private AbstractFactory factory;
public OrderPizza(AbstractFactory factory) {
//通过构造器利用组合的方式
setFactory(factory);
}
//通过set利用组合的方法
public void setFactory(AbstractFactory factory) {
this.factory = factory;
do {
String orderType = getType();
Pizza pizza = null;
pizza = factory.createPizza(orderType);
if (pizza == null) {
System.out.println("订购失败!");
} else {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
} while (true);
}
//写一个方法 可以获取客户希望订购的pizza
private String getType() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请在下面输入你要购买的Pizza");
String pizza = reader.readLine();
return pizza;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
抽象工厂与简单工厂的对比:
抽象工厂模式呢,相当于抽象了两层,一层是抽象层,另一层是实现抽象层的具体层,这样后期的拓展和维护会很方便。但是简单工厂模式呢,他比较“楞”,他直接抽取成了一层具体层,完全没有考虑后期的拓展和维护。
抽象工厂与工厂方法的对比:
他们最终都是创建对象,但方式有所不同,工厂方法采用的是继承,抽象工厂采用的是组合。而抽象工厂中蕴含着很多的工厂方法,所以说抽象工厂可以有很多的工厂方法,所以抽象工厂的相比于工厂方法的另一个优点就是可以把一群相关的产品集合起来(之前提到的各种蔬菜,各种酱等等等),但是同时也带来了反作用,如果新增一个产品,那么接口将被修改,那是很严重的。所以抽象工厂需要一个很大的接口,因为抽象工厂是创建整个产品家族的,而工厂方法是创建单个产品的,所以说抽象工厂中蕴含着工厂方法。
HeadFirst中,这段采访很精彩
简单工厂在jdk源码中的引用:
在调用createCalendar中,
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}
今天的文章工厂模式超详解!分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/25421.html