哈啰,各位小伙伴,这里是每天进步一点点的花栗鼠小K
“这几天都在忙活硕士毕业的材料,满脑子都是盖章、扫描、学位信息上报等各种要命的东西,恍惚间,就到了该交作业的日子,想着之前开了个面试经验分享的口子,但好久没有写面试的东西了。今天就补上一篇面试必问的一part:设计模式
。“
回顾整个面试,小K发现面试官的问题,问的范围还是挺集中的。一般都绕不开那么几个问题
你了解设计模式吗? 你常用哪些设计模式? 挑一些你最熟悉的设计模式讲一下 AA设计模式和BB设计模式有什么区别?
面对面试官的死亡四连问,大部分人都能扛到前三问,但是没系统学过设计模式的同学,可能第四问有点吃力。
那么今天小K带大家探秘一下第四问的常客:工厂类设计模式。
首先,我们先搞清楚是什么
01
—
什么是工厂模式
简单点
工厂模式(Factory Pattern)
属于创建型模式,它提供了一种创建对象的最佳方式,使得在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象,换句话说就是实现了使用者和创建者的分离。
学习就是刚解决一个老问题,就出现一个新问题的过程,可能又有小伙伴疑惑,什么是创建型模式。好吧,如下
创建型模式(Creational Pattern)
对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。
该模式下有三个子类
简单工厂模式(Simple Factory)
工厂方法模式(Factory Method)
抽象工厂模式(Abstract Factory)
接下来,小K一一介绍这三个子类
02
—
简单工厂模式
简单工厂是由一个工厂对象决定创建哪一个产品类的实例
该模式并不是23种设计模式之一,相比于工厂方法模式
和抽象工厂模式
的正统地位,它有点像捡来的孩纸
其 UML
如图

简单工厂模式包含三个角色
Factory
:即工厂类, 简单工厂模式的核心部分,负责实现创建所有产品的内部逻辑;工厂类可以被外界直接调用,创建所需对象
Product
:抽象类产品, 它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象
ConcreteProduct
:具体产品, 它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。它要实现抽象产品中声明的抽象方法
举个🌰
生产一部手机,创建了手机接口和具体手机的类
public interface MobilePhone {
public void makeCall();
public void surfInternet();
}
// 华为手机
public class HuaWei implements MobilePhone{
@Override
public void makeCall() { System.out.println("华为手机通话"); }
@Override
public void surfInternet() { System.out.println("华为手机上网"); }
}
// 苹果手机
public class Apple implements MobilePhone{
@Override
public void makeCall() { System.out.println("苹果手机通话"); }
@Override
public void surfInternet() { System.out.println("苹果手机上网"); }
}
// 小米手机
public class XiaoMi implements MobilePhone{
@Override
public void makeCall() { System.out.println("小米手机通话"); }
@Override
public void surfInternet() { System.out.println("小米手机上网"); }
}
华为、苹果、小米手机都继承自 MobilePhone
,为了便于管理对象的创建,通过一个简单的工厂模式来创建这些类型的对象。简单工厂模式的代码如下
public class SimpleFactory {
public static MobilePhone createPhone(String brand) {
MobilePhone phone = null;
if (brand.equalsIgnoreCase("huawei")) {
phone = new HuaWei();
} else if (brand.equalsIgnoreCase("xiaomi")) {
phone = new XiaoMi();
} else if (brand.equalsIgnoreCase("apple")) {
phone = new Apple();
}
return phone;
}
}
在 MobileFactory
的 createPhone
函数中我们需要传递一个参数,通过该参数来创建不同的手机对象,例如华为、苹果、小米。
MobileFactory
中只有一个静态函数 createPhone
通过该函数可以创建多种对象类型,这就是简单工厂模式的核心定义,所以也称为 静态方法工厂模式
。
简单工厂模式的优缺点
优点
简单工厂模式的名称就源自于其简单 明确了各自的职责和权利,有利于整个软件体系结构的优化 缺点
实际应用中,很可能产品是一个多层次的树状结构, 可能不太适用了 它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了 当具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利
为了解决上述缺点,于是产生了工厂方法模式
03
—
工厂方法模式
工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法是一个类的实例化延迟到其子类。
其 UML
如图

工厂方法模式包含 4 个角色
Product
:抽象产品,定义工厂方法所创建的对象的接口,也就是实际需要使用的对象的接口
ConcreteProduct
:具体产品,具体的Product
接口的实现对象
Factory
:工厂接口,申明工厂方法,通常返回一个Product
类型的实例对象
ConcreteFactory
:工厂实现,覆盖Factory
定义的工厂方法,返回具体的Product
实例
此处小K在简单工厂模式的代码基础上稍作改动,增加工厂方法接口,同时该接口中包含一个 createPhone
抽象方法,返回值为 MobilePhone
public interface FactoryMethod {
MobilePhone createPhone();
}
然后定义三个具体工厂类型 HuaWeiFactory
、AppleFactory
、XiaoMiFactory
,分别用于创建华为、苹果、小米手机,具体代码如下
// 华为手机工厂
public class HuaWeiFactory implements FactoryMethod{
@Override
public MobilePhone createPhone() {
return new HuaWei();
}
}
// 苹果手机工厂
public class AppleFactory implements FactoryMethod{
@Override
public MobilePhone createPhone() {
return new Apple();
}
}
// 小米手机工厂
public class XiaoMiFactory implements FactoryMethod{
@Override
public MobilePhone createPhone() {
return new XiaoMi();
}
}
这时想要生产某一产品,就需要先构建该产品的生产工厂
public static void main(String[] args) {
FactoryMethod concreteFactory;
// 华为工厂生产华为手机
concreteFactory= new HuaWeiFactory();
MobilePhone huaWei = concreteFactory.createPhone();
huaWei.makeCall();
// 小米工厂只生产小米手机
concreteFactory= new XiaoMiFactory();
MobilePhone xiaoMi = concreteFactory.createPhone();
xiaoMi.makeCall();
}
工厂方法模式的优缺点
优点
一个调用者想创建一个对象,只要知道其名称就可以了。 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 屏蔽产品的具体实现,调用者只关心产品的接口。 缺点
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
工厂方法模式和简单工厂的区别主要有两点
工厂方法需要定义抽象工厂类或接口,例如上述的 MobileFactory
具体的对象由具体的工厂类(如 HuaWeiFactory
)来创建,并且每个工厂只创建一类对象。
04
—
抽象工厂模式
抽象工厂模式为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类
其 UML
如图

抽象工厂模式主要包含四个角色
抽象工厂模式包含的角色(要素):
AbstractFactory
:抽象工厂,用于声明生成抽象产品的方法
ConcreteFactory
:具体工厂,实现抽象工厂定义的方法,具体实现一系列产品对象的创建
AbstractProduct
:抽象产品,定义一类产品对象的接口
ConcreteProduct
:具体产品,通常在具体工厂里,会选择具体的产品实现,来创建符合抽象工厂定义的方法返回的产品类型的对象。
抽象工厂和工厂方法相似,但是其需要对每一个产品功能进行抽象
工厂类如下
public interface AbstractFactory {
MakeCall makeCall();
SurfInternet surfInternet();
}
public class AppleFactory implements AbstractFactory{
@Override
public MakeCall makeCall() { return new AppleMakeCall(); }
@Override
public SurfInternet surfInternet() { return new AppleSurfInternet(); }
}
public class HuaWeiFactory implements AbstractFactory{
@Override
public MakeCall makeCall() { return new HuaWeiMakeCall(); }
@Override
public SurfInternet surfInternet() { return new HuaWeiSurfInternet(); }
}
产品功能类如下
// 通话功能
public interface MakeCall {
void communicate();
}
public class AppleMakeCall implements MakeCall{
@Override
public void communicate() {
System.out.println("苹果正在通话");
}
}
public class HuaWeiMakeCall implements MakeCall{
@Override
public void communicate() {
System.out.println("华为正在通话");
}
}
// 上网功能
public interface SurfInternet {
void online();
}
public class AppleSurfInternet implements SurfInternet{
@Override
public void online() {
System.out.println("苹果正在上网");
}
}
public class HuaWeiSurfInternet implements SurfInternet{
@Override
public void online() {
System.out.println("华为正在上网");
}
}
使用时,需要针对每个产品及功能,进行实例化
public static void main(String[] args) {
AbstractFactory huaWeiFactory = new HuaWeiFactory();
MakeCall makeCall = huaWeiFactory.makeCall();
makeCall.communicate(); //华为专用通话
AbstractFactory appleFactory = new AppleFactory();
SurfInternet surfInternet = appleFactory.surfInternet();
surfInternet.online(); // 苹果专用上网
}
可以看到,抽象工厂实际上就是工厂方法的升级版,它的一个工厂类能够生产多个不同类型的、相关联或者相互依赖的对象。
抽象工厂与简单工厂也很类似,只是简单工厂通过一个静态函数创建不同类型的对象,而抽象工厂通过工厂子类的多个函数创建多个不同类型的对象
抽象工厂模式的优缺点
优点
抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。 缺点
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。
开闭原则:软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的
05
—
适用场景
不管是简单工厂模式,工厂方法模式还是抽象工厂模式,他们具有类似的特性,所以他们的适用场景也是类似的。
首先,作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
其次,工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。
再次,由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。
工厂模式在我们这些Java
码农身边可以说无处不在。
小到JDK
中的 calendar
Calendar calendar = Calendar.getInstance();
还有常用的日志框架slf4J
private final static Logger logger = LoggerFactory.getLogger(HelloWord.class);
当然,最为猿所乐道的就是 Spring
中的 Bean
,IOC
通过 FactoryBean
对 Bean
进行管理,想了解更多关于Bean
的内容,可以找下栗子为《一文搞懂bean的生命周期》
说来Bean
可以由反射和单例模式进行构建,下期要不要讲这个呢?
06
—
总结
本文主要介绍了面试常遇到的设计模式问题,详细的比对了工厂模式的三个子类:简单工厂、工厂方法和抽象工厂。既有UML
图,又有具体实现,还包括优缺点分析,感兴趣的小伙伴可以仔细阅读一下哟
这里是花栗鼠小K,下次有🌰,我再来,拜拜~~~
关注六只栗子,面试不迷路
作者 花栗鼠小K
编辑 一口栗子
原文始发于微信公众号(六只栗子):8分钟帮你理清工厂模式
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/88648.html