设计模式剖析——抽象工厂模式Abstract Factory Pattern
含义
- 与工厂方法模式相比,概念有些不一样。有抽象零件、抽象产品、抽象工厂。用零件来组装出产品,组装出的产品才是完整的产品。
- 既然一个完整产品需要多个零件,那么每种具体工厂自然也需要可以同时生产出多种零件(指工厂里会有几种
createXXX
方法)。 - 强调什么抽象产品族类、抽象产品类是没有意义的。这只是因为继承树中,有一种抽象基类分化出两种更具体的抽象基类罢了。
- 也许你会用到泛型或者反射,但记住,用这些技术的目的是为了不让客户端了解到具体零件类或者具体产品类,而不是为了炫技。
UML图
还是觉得给出实际例子的UML图更加易懂吧。这里解释一下这些类的含义:
- nonConcrete包里有抽象的类;concrete包中有具体的类。
- 零件有手机phone、手机壳phoneShell、手机膜phoneFilm。当给手机套上壳、贴上膜的时候,才算这个一个完整的产品。
- phoneShell和phoneFilm继承了同一个接口item,因为它们都属于是配件一类的东西。
- 假定与oppo手机配套的是软壳softShell、非全屏膜almostFilm;与vivo手机配套的是硬壳hardShell、全屏膜fullFilm。
- 这三种零件的具体类都可以有更具体的说明,通过构造函数给出。
示例代码
首先是nonConcrete包中的抽象类:
package nonConcrete;//item.java file
interface item {String attribute();
}//这是另一个文件的内容,但此处省略了package nonConcrete。后面将作同样处理,即省略package语句。
//phoneShell.java file
public abstract class phoneShell implements item{protected String whichShell;protected phoneShell(String in){whichShell = in;}
}//phoneFilm.java file
public abstract class phoneFilm implements item{protected String whichFilm;protected phoneFilm(String in){whichFilm = in;}
}//phone.java file
public abstract class phone {public String whichVision;public phoneShell myShell;public phoneFilm myFilm;protected phone(String in){whichVision = in;}public phone addShell(phoneShell shell){myShell = shell;return this;}public phone addFilm(phoneFilm film){myFilm = film;return this;}public abstract void boot();//开机
}//factory.java file
public abstract class factory {public static factory getFactory(String classname){factory f = null;try {f = (factory)Class.forName(classname).newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return f;}public abstract phoneShell createShell(String shellType);public abstract phoneFilm createFilm(String filmType);public abstract phone createPhone(String phoneType);
}
- 注意到抽象手机类phone有三个成员变量,但构造函数只会初始化其中一个。其余两个成员交给其另外两个成员函数来添加,且为了方便流式操作,所以这两个函数都
return this
。 - 抽象工厂类factory定义好了三种抽象方法,分别返回三种零件。还有一个静态方法
getFactory
,用来反射出具体工厂类的对象。这样便可以避免客户端了解到具体工厂类。 - 上一条如果不用反射,我想只能通过内部类和静态成员来解决:用静态内部类来继承并实现factory,因为从逻辑上来讲这里不应该持有外部类对象的引用(或者使用在static context语境下的匿名内部类,这种情况也不会持有外部类对象的引用);然后实例化静态内部类,并将实例向上转型赋值给一个factory类型的静态成员变量。
然后是concrete包中的具体类:
package concrete;//softShell.java file
import nonConcrete.phoneShell;class softShell extends phoneShell {softShell(String type){super(type);}@Overridepublic String attribute(){//实现了item接口的方法return this.whichShell+"软壳";}
}//hardShell.java file
import nonConcrete.phoneShell;class hardShell extends phoneShell {hardShell(String type){super(type);}@Overridepublic String attribute(){return this.whichShell+"硬壳";}
}//almostFilm.java file
import nonConcrete.phoneFilm;class almostFilm extends phoneFilm {almostFilm(String type){super(type);}public String attribute(){return this.whichFilm+"非全屏膜";}
}//fullFilm.java file
import nonConcrete.phoneFilm;class fullFilm extends phoneFilm {fullFilm(String type){super(type);}public String attribute(){return this.whichFilm+"全屏膜";}
}//oppoPhone.java file
import nonConcrete.phone;class oppoPhone extends phone {oppoPhone(String in){super(in);}@Overridepublic void boot(){System.out.println("oppo"+this.whichVision+"手机:带有"+this.myShell.attribute()+"和"+this.myFilm.attribute());}
}//vivoPhone.java file
import nonConcrete.phone;class vivoPhone extends phone {vivoPhone(String in){super(in);}@Overridepublic void boot(){System.out.println("vivo"+this.whichVision+"手机:带有"+this.myShell.attribute()+"和"+this.myFilm.attribute());}
}//oppoFactory.java file
import nonConcrete.*;public class oppoFactory extends factory {public phoneShell createShell(String shellType){return new softShell(shellType);}public phoneFilm createFilm(String filmType){return new almostFilm(filmType);}public phone createPhone(String phoneType){return new oppoPhone(phoneType);}
}//vivoFactory.java file
import nonConcrete.*;public class vivoFactory extends factory {public phoneShell createShell(String shellType){return new hardShell(shellType);}public phoneFilm createFilm(String filmType){return new fullFilm(filmType);}public phone createPhone(String phoneType){return new vivoPhone(phoneType);}
}
注意两个具体工厂类的权限修饰符必须是public,如果不是,那么下面的factory oppoFac = factory.getFactory("concrete.oppoFactory");
将会报错java.lang.IllegalAccessException: Class nonConcrete.factory can not access a member of class concrete.oppoFactory with modifiers ""
,因为反射是在nonConcrete.factory的静态方法中进行的,需要在此处可以访问到concrete.oppoFactory。但那些具体零件类的权限可以是默认,因为它们只需要被具体工厂类访问到就好。
顺便看一下报错的调用栈,追一下源码:
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)at java.lang.Class.newInstance(Class.java:436)
//Reflection.javapublic static void ensureMemberAccess(Class<?> var0, Class<?> var1, Object var2, int var3) throws IllegalAccessException {if (var0 != null && var1 != null) {if (!verifyMemberAccess(var0, var1, var2, var3)) {//调用此函数返回了假,说明没有通过验证throw new IllegalAccessException("Class " + var0.getName() + " can not access a member of class " + var1.getName() + " with modifiers \"" + Modifier.toString(var3) + "\"");}} else {throw new InternalError();}}
public static boolean verifyMemberAccess(Class<?> var0, Class<?> var1, Object var2, int var3) {//var0是调用者,var1是被实例化者boolean var4 = false;boolean var5 = false;if (var0 == var1) {return true;} else {if (!Modifier.isPublic(getClassAccessFlags(var1))) {//先检查被实例者是不是public的var5 = isSameClassPackage(var0, var1);//再检查是不是同一个包var4 = true;if (!var5) {return false;}}//后面还有,不贴上来了 }
然后是在默认包中的测试类:
import nonConcrete.*;public class Main {public static void main(String[] args) {factory oppoFac = factory.getFactory("concrete.oppoFactory");phoneShell oppoS = oppoFac.createShell("透明的");phoneFilm oppoF = oppoFac.createFilm("抗蓝光的");phone oppo = oppoFac.createPhone("R15").addShell(oppoS).addFilm(oppoF);//组装产品oppo.boot();factory vivoFac = factory.getFactory("concrete.vivoFactory");phoneShell vivoS = vivoFac.createShell("抗摔的");phoneFilm vivoF = vivoFac.createFilm("高清的");phone vivo = vivoFac.createPhone("X27").addShell(vivoS).addFilm(vivoF);vivo.boot();}
}/*output:
oppoR15手机:带有透明的软壳和抗蓝光的非全屏膜
vivoX27手机:带有抗摔的硬壳和高清的全屏膜
*/
从测试类导入的包中可以看出,客户端不需要了解到任何具体类,当然这里也是多亏了反射的功劳。
优缺点
- 当抽象零件类不需要增加时符合【开闭原则】,只需要增加具体零件类和具体工厂类即可。
- 当抽象零件类需要增加时则不符合【开闭原则】,此时已存在的具体工厂类需要增加函数。对于本文例子,情况则可以是手机还需要镜头膜才能出厂。
- 上面两点总结为:开闭原则的倾斜性。
应用场景
- 在产品类中还需要有零件类的概念时。
- 工厂类中需要有多种创建不同种类产品的方法时。
设计模式剖析——抽象工厂模式Abstract Factory Pattern相关推荐
- 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)
原文:乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern) [索引页] [源码下载] 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Facto ...
- 【设计模式】抽象工厂模式 Abstract Factory Pattern
简单工厂模式是一个工厂类根据工厂方法的参数创建不出不同的产品, 工厂方法模式是每一个产品都有一个一一对应的工厂负责创建该产品.那么今天要讲的抽象工厂模式是一个工厂能够产生关联的一系列产品.抽象工厂模式 ...
- Net设计模式之抽象工厂模式(Abstract Factory Pattern)(1)
一.抽象工厂模式简介(Bref Introduction) 抽象工厂模式(Abstract Factory Pattern),提供一个创建一系列相关或者相互依赖对象的接口,而无需制定他们的具体类.优点 ...
- 设计模式 - 抽象工厂模式(abstract factory pattern) 详解
抽象工厂模式(abstract factory pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/270916 ...
- 抽象工厂模式 Abstract Factory Pattern
源地址 抽象工厂模式 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创建型模式,它提供了一种创建 ...
- 抽象工厂模式-Abstract Factory Pattern
抽象工厂模式-Abstract Factory Pattern 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类.抽 ...
- 设计模式之抽象工厂模式(Abstract Factory)摘录
面向对象系统的分析和设计实际上追求的就是两点:高内聚(Cohesion)和低耦合(Coupling). 23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式包括:1.Fa ...
- 设计模式之抽象工厂模式---abstract factory
模式的介绍 模式的定义 Provide an interface for creating families of related or dependent objects without speci ...
- 极速理解设计模式系列:10.抽象工厂模式(Abstract Factory Pattern)
五个角色:抽象产品角色(AbstractProduct).具体产品角色(Product).抽象工厂角色(AbstractFactory).具体工厂角色(ConcreteFactory).客户端(Cli ...
最新文章
- golang os.Rename 移动文件 报错 invalid cross-device link 解决方法
- 利用钥匙串,在应用里保存用户密码的方法
- Text-CNN-文本分类-keras
- 使用docker中的apline部署自己的golang的后端代码(添加制作静态服务器的注意点)...
- php 读取三级分类,php excel 导入 导入三级分类 表格应该怎么设计才能得到想要的数据格式?汗血宝马...
- esmini LongSpeedAction修改
- 高通Android平台下关于display部分的几个关键问题
- 计算机表演赛bug,只会编程序,敲代码,找bug?不,他们保研浙大、去美国进修……...
- 自己动手写PHP框架(三)
- gps北斗高精度卫星时间同步系统应用案例
- maxscale连接mysql_MaxScale实现mysql读写分离,负载均衡
- 10个成语理解项目管理的价值观和方法论
- 不小心把桌面上的计算机图标删了怎么办,如何删除桌面图标,不小心把桌面上的我的电脑图标删除了怎么办...
- C语言头歌educoder实训作业答案分享 指针(一)
- USRP X310使用的准备工作--Linux进行FPGA image烧录
- 【友盟+】营销大数据论坛完美收官:数据驱动营销智能
- ego-motion 自我运动
- pdf在线翻译_24个PDF在线小工具,免费在线翻译PDF文档。
- C++键盘记录器源码
- ip地址、子网掩码、网段、子网划分