设计模式之工厂方法模式(Java实现)
@[toc]
前言
本篇博客是关于工厂方法模式的实现,若文章中出现相关问题,请指出!
对应代码地址:Gitee(demo-exer/ java-Lear23designpatterns)、Github(java-demo/ java-Lear23designpatterns)
所有博客文件目录索引:博客目录索引(持续更新)
一、认识工厂模式
工厂模式定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂中,实现了创建者与调用者的分离!
工厂模式分类:简单工厂模式
、工厂方法模式
、抽象工厂模式
。
简单工厂模式
:将被创建的对象称为"产品",把创建产品的对象称为"工厂",若是产品不多,可通过使用一个工厂类即可完成,若是出现新的产品,需要去修改原有的方法,这违法了开闭原则。由于在简单工厂中创建对象的方法是static
,所以又被称为静态工厂模式。该模式并不算在GoF23种设计模式之中。- 应用场景:
Spring
中的BeanFactory
。
- 应用场景:
工厂方法模式
:解决了简单工厂模式违反开闭原则,在工厂方法模式中每一个产品都对应着一个工厂类,满足了开闭原则
,就是需要付出更多的代价,若是产品特别多那么整体代码量会巨大。- 应用场景:
Spring
与Mybatis
的结合(FactoryBean
接口)。
- 应用场景:
抽象工厂模式
:围绕一个超级工厂来创建其他工厂,该超级工厂又称为其他工厂的工厂。
二、引出工厂模式
我们通常去创建一个对象的实例需要通过自己去手动new
来创建实例,这种方式又称为无工厂模式,对于一些较复杂且需要多项配置时就比较头疼了,需要一个个填入到构造器中,造成不必要的麻烦!
下面代码就通过手动new
的方式来获取实例:
interface Car {
void name();
}
//宝马
class BMW implements Car{
@Override
public void name() {
System.out.println("宝马");
}
}
//保时捷
class Porsche implements Car{
@Override
public void name() {
System.out.println("保时捷");
}
}
//消费者
public class Customer {
public static void main(String[] args) {
//通过手动new的方式来获取产品实例
Car bmw = new BMW();
Car porsche = new Porsche();
bmw.name();
porsche.name();
}
}
在日常开发中,凡是需要生成复杂对象的地方,都可以尝试考虑使用工厂模式
来代替!
三、工厂模式实现
3.1、简单工厂模式
简单工厂模式:由于工厂的方法是
static
所以也叫做静态工厂模式。简单工厂模式有一个具体的工厂类,可以生成多个不同的产品,属于创建型设计模式。(但该模式并不在GoF23种设计模式中)
好处:
- 相对于无工厂模式,我们不再通过
new
来获取自己想要创建的实例,而是通过一个工厂类方法,只需要传入指定的参数就能够获取到我们想要的对象实例。 - 使用工厂方法时无需只要知道执行的类名,只需要知道能够创建实例的参数即可。
缺点:
- 一旦新增产品,我们就需要回到原有的工厂类创建实例方法中进行修改,否则无法扩展其他产品,这违反
开闭原则
(扩展功能,不要修改原来的方法)。 - 简单工厂模式工厂类单一,负责所有产品的创建,职责过重一旦出现异常整个系统都会受到影响,若是产品量过多,工厂类创建实例方法会非常臃肿。违法了
单一职责原则
。
应用场景:
- 对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
简单工厂模式实现:
interface Car {
void name();
}
//宝马
class BMW implements Car{
@Override
public void name() {
System.out.println("宝马");
}
}
//保时捷
class Porsche implements Car{
@Override
public void name() {
System.out.println("保时捷");
}
}
public class CarFactory {
//传入指定名称来获取具体产品实例
public static Car getCar(String name){
if("宝马".equals(name)){
return new BMW();
}else if("保时捷".equals(name)){
return new Porsche();
}
return null;
}
}
public class Main {
public static void main(String[] args){
//通过工厂类来创建指定产品实例
Car bmw = CarFactory.getCar("宝马");
Car porsche = CarFactory.getCar("保时捷");
bmw.name();
porsche.name();
}
}
- 添加了一个汽车工厂类
CarFactory
,其中添加一个创建产品方法getCar()
根据传入参数来创建实例。 - 其中工厂创建方法通过
if..else
来判断创建也可以使用switch.case.
进行创建。
说明:在简单工厂模式中,若是增加了其他产品则需要回到原来的方法中进行修改操作,这就违背了开闭原则,之后通过工厂方法模式则能够遵守该规则。不过有一说一,对于这种简单工厂模式在实际应用中会大量使用。
3.2、工厂方法模式
工厂方法模式:是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足
开闭原则
,但是需要付出一定代价(对于产品很多并且零件很多情况下,造成创建工厂类过多情况)。
优点:
- 用户只需要知道具体工厂的名称即可得到所需要的产品,无需知道产品创建的过程。
- 更具有灵活性,当新增产品时,我们只需要创建一个相对应的工厂类,满足
开闭原则
。 - 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足
迪米特法则
、依赖倒置原则
和里氏替换原则
。
缺点:
- 若是产品类过多,那么也就意味着创建对应数量的产品工厂,增加了复杂度。
- 增加了系统的抽象性和理解程度。
工厂方法模式实现:
在工厂方法模式中,我们添加一个工厂接口,一个产品对应一个工厂类,该工厂类实现该接口,顾客则通过指定产品的工厂类方法来获取产品实例,可见下图:
通过使用一个接口来规范工厂的获取实例方法:
interface Car {
void name();
}
//宝马
class BMW implements Car{
@Override
public void name() {
System.out.println("宝马");
}
}
//保时捷
class Porsche implements Car{
@Override
public void name() {
System.out.println("保时捷");
}
}
//新增一个工厂接口
interface Factory{
Car getCar();
}
public class BMWFactory implements CarFactory{
@Override
public Car getCar() {
return new BMW();
}
}
public class PorscheFactory implements CarFactory{
@Override
public Car getCar() {
return new Porsche();
}
}
public class Main {
public static void main(String[] args){
//通过对应产品的工厂类来获取实例
Car bmw = new BMWFactory().getCar();
Car porsche = new PorscheFactory().getCar();
bmw.name();
porsche.name();
}
}
看一下多个接口及类的UML
图:
我们能够看到结构变得更加清晰了,想要哪个汽车类型即可从对应类型的工厂中拿到,但是随着产品的增多,工厂类也会增多,增加了复杂度。
总结
简单工厂模式
(静态工厂模式):其并不属于GoF23种设计模式的范畴中,并在某种程度上并不符合设计原则,但实际使用最多。
工厂方法模式
:符合开闭原则,当添加新的产品时不需要更改原有的方法代码,直接通过增加新的工厂类实现扩展。
这两种模式都是针对于某个产品!
参考资料
[1]. C语言中文网—简单工厂模式
- 点赞
- 收藏
- 关注作者
评论(0)