设计模式——工厂模式(Factory Pattern)
工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。该模式用于封装和管理对象的创建,是一种创建型模式。本文从一个具体的例子逐步深入分析,来体会三种工厂模式的应用场景和利弊。
一、简单工厂模式
用简单的话来说,简单工厂模式是工厂模式最简单的一种,他可以用一些简单的方法去隐藏对象的细节,一般只需告诉工厂类所需的类型就可以,工厂类会返回你需要的产品类,但你在客户端看到的只是产品的抽象对象,不需要关心返回是什么类。客户端唯一知道的就是具体子类,也就是工厂子类。除了这一点,基本是达到依赖倒转原则的要求罢了!
如果我们不去用工厂类,那客户端会每次使用不同的子类的时候,都需要知道到底是用哪一个类,要是累比较少,那没有什么为题。但是当类比较多的时候,管理起来会非常麻烦,就需要做大量的替换,可能还会发生错误。如果使用工厂类之后,就不会发生这种问题了,不管里面有多少类,我们需要知道类型号就可以了。所以简单工厂模式一般应该于程序中大部分地方都只使用其中一种产品,工厂类也不用频繁创建产品类的情况。
举个栗子
我喜欢吃面条,抽象一个面条基类,(接口也可以),这是产品的抽象类。
public abstract class INoodles {
/**
* 描述每种面条啥样的
*/
public abstract void desc();
}
先来一份兰州拉面(具体的产品类):
class LzNoodles extends INoodles {
public LzNoodles() {
this.desc();
}
@Override
public void desc() {
System.out.println("兰州拉面 上海的好贵 家里才5 6块钱一碗");
}
}
再是程序员加班必备也要吃泡面(具体的产品类):
class PaoNoodles extends INoodles {
public PaoNoodles() {
this.desc();
}
@Override
public void desc() {
System.out.println("泡面好吃 可不要贪杯");
}
}
还有我最爱吃的炸酱面(具体的产品类):
class ZhaJiangNoodles extends INoodles {
public ZhaJiangNoodles() {
this.desc();
}
@Override
public void desc() {
System.out.println("还是炸酱面最好吃!");
}
}
准备工作做完了,我们来到一家“简单面馆”(简单工厂类),菜单如下:
public class SimpleNoodlesFactory {
public static final int TYPE_LZ = 1;//兰州拉面
public static final int TYPE_PM = 2;//泡面
public static final int TYPE_ZJ = 3;//炸酱面
public static INoodles createNoodles(int type) {
switch (type) {
case TYPE_LZ:
return new LzNoodles();
case TYPE_PM:
return new PaoNoodles();
case TYPE_ZJ:
default:
return new ZhaJiangNoodles();
}
}
}
简单面馆就提供三种面条(产品),你说你要啥,他就给你啥。这里我点了一份炸酱面:
/**
* 简单工厂模式
*/
INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_ZJ); //还是炸酱面最好吃!
优点
1.隐藏了对象创建的细节,将产品的实例推迟到子类中去。
2.客户端无需关心使用时哪一个产品,只需要知道用哪一个工厂就行了,提供的类型也可以用比较便于识别的字符串。
3.方便添加到新的产品子类中,每次字需要修改工厂传递的类型值就可以了。
4.遵循了依赖倒转的原则。
缺点
1.要求产品子类的类型差不多,使用的方法都相同,如果累比较多一些的话,所有的类又要添加到一种方法,则会是非常麻烦的事情。或者还有一种,就是一种类另一种类有几种方法不一样,客户端无法找到是哪一个子类,也不能去调用这几个不同的方法了。
二、工厂模式
工厂模式基本与简单工厂模式差不多的,但是简单工厂模式每次添加一个产品类都必须在工厂类中添加,违反了“开放-封闭”原则。而工厂模式则是把原先“判断生成产品类”的模式改成了“判断生成工厂子类”的模式,然后每次添加产品子类的时候,只需要添加工厂子类即可。这样就遵循了“开放-封闭”原则
但这其实也有问题,如果产品数量足够多,要维护的量就会增加,好在一般工厂子类只用来生成产品类,只要产品子类的名称不发生变化,那么基本工厂子类就不需要修改,每次只需要修改产品子类就可以了。
同样工厂模式一般应该于程序中大部分地方都只使用其中一种产品,工厂类也不用频繁创建产品类的情况。这样修改的时候只需要修改有限的几个地方即可。
常用的场景
工厂模式与简单工厂模式基本是一致的,有一写不同就是改进了简单工厂模式中的开发-封闭原则,使用工厂模式更具有弹性。将实例化的过程推迟到子类中,由子类决定实例化哪一个。
优点
基本与简单工厂模式一致,多的一点优点就是遵循了开放-封闭原则,使得模式的灵活性更强。
缺点
与简单工厂模式差不多。
举个栗子
与上述简单工厂模式相同的是,与产品相关的接口、实现类都固定不变。
但是要定义一系列与工厂相关的类与接口。
AbstractFactory类:生产不同产品的工厂的抽象类
public interface AbstractFactory {
INoodles createNoodles();
}
LzNoodlesFactory类:生产兰州拉面的工厂
public class LzNoodlesFactory implements AbstractFactory{
@Override
public INoodles createNoodles() {
return new LzNoodles();
}
}
PaoNoodlesFactory类:生产泡面的工厂
public class PaoNoodlesFactory implements AbstractFactory{
@Override
public INoodles createNoodles() {
return new PaoNoodles();
}
}
ZhaJiangNoodlesFactory类:生产炸酱面的工厂
public class ZhaJiangNoodlesFactory implements AbstractFactory{
@Override
public INoodles createNoodles() {
return new ZhaJiangNoodles();
}
}
演示:
/**
* 工厂模式
*/
public class Demo {
public static void main(String[] arg) {
AbstractFactory lzNoodlesFactory = new LzNoodlesFactory();
AbstractFactory paoNoodlesFactory = new PaoNoodlesFactory();
AbstractFactory zhaJiangNoodlesFactory= new ZhaJiangNoodlesFactory();
lzNoodlesFactory.createNoodles(); // 兰州拉面 上海的好贵 家里才5 6块钱一碗
paoNoodlesFactory.createNoodles(); // 泡面好吃 可不要贪杯
zhaJiangNoodlesFactory.createNoodles(); //还是炸酱面最好吃!
}
}
三、抽象工厂模式
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构
举个栗子
我们继续通过面条产品生产的例子来解释该模式。
大家都知道我们吃面的时候可能还会配汤,所以我们再创造一个汤的产品类。
Soup类:定义汤产品的接口
public interface Soup {
void make();
}
MuttonSoup类:定义羊肉汤产品
public class MuttonSoup implements Soup {
public MuttonSoup() {
this.make();
}
@Override
public void make() {
System.out.println("羊肉汤好喝!");
}
}
BeefSoup类:定义牛肉汤产品
public class BeefSoup implements Soup {
public BeefSoup () {
this.make();
}
@Override
public void make() {
// TODO Auto-generated method stub
System.out.println("牛肉汤好喝!");
}
}
ChickenSoup类:定义鸡汤产品
public class ChickenSoup implements Soup {
public ChickenSoup () {
this.make();
}
@Override
public void make() {
// TODO Auto-generated method stub
System.out.println("鸡汤好喝!");
}
}
下面需要修改工厂相关的类的定义:
AbstractFactory类:增加Soup产品制造接口
public interface AbstractFactory {
INoodles createNoodles();
Soup make();
}
LzNoodlesFactory类:兰州拉面的工厂增加羊肉汤产品
public class LzNoodlesFactory implements AbstractFactory{
@Override
public INoodles createNoodles() {
return new LzNoodles();
}
@Override
public Soup make() {
return new MuttonSoup();
}
}
PaoNoodlesFactory类:生产泡面的工厂增加牛肉汤产品
public class PaoNoodlesFactory implements AbstractFactory{
@Override
public INoodles createNoodles() {
return new PaoNoodles();
}
@Override
public Soup make() {
return new BeefSoup();
}
}
ZhaJiangNoodlesFactory类:生产炸酱面的工厂增加鸡汤产品类
public class ZhaJiangNoodlesFactory implements AbstractFactory{
@Override
public INoodles createNoodles() {
return new ZhaJiangNoodles();
}
@Override
public Soup make() {
return new ChickenSoup();
}
}
演示:
/**
* 工厂模式
*/
public class Demo {
public static void main(String[] arg) {
AbstractFactory lzNoodlesFactory = new LzNoodlesFactory();
AbstractFactory paoNoodlesFactory = new PaoNoodlesFactory();
AbstractFactory zhaJiangNoodlesFactory= new ZhaJiangNoodlesFactory();
lzNoodlesFactory.createNoodles(); // 兰州拉面 上海的好贵 家里才5 6块钱一碗
paoNoodlesFactory.createNoodles(); // 泡面好吃 可不要贪杯
zhaJiangNoodlesFactory.createNoodles(); //还是炸酱面最好吃!
lzNoodlesFactory.make(); //羊肉汤好喝!
paoNoodlesFactory.make(); //牛肉汤好喝!
zhaJiangNoodlesFactory.make(); //鸡汤好喝!
}
}
抽象工厂模式就变得比工厂模式更为复杂,就像上面提到的缺点一样,工厂模式和简单工厂模式要求产品子类必须要是同一类型的,拥有共同的方法,这就限制了产品子类的扩展。于是为了更加方便的扩展,抽象工厂模式就将同一类的产品子类归为一类,让他们继承同一个抽象子类,我们可以把他们一起视作一组,然后好几组产品构成一族。
优点
1.封装了产品的创建,使得不需要知道具体是哪种产品,只需要知道是哪个工厂就行了。
2.可以支持不同类型的产品,使得模式灵活性更强。
3.可以非常方便的使用一族中间的不同类型的产品。
缺点
1.结构太过臃肿,如果产品类型比较多,或者产品族类比较多,就会非常难于管理。
2.每次如果添加一组产品,那么所有的工厂类都必须添加一个方法,这样违背了开放-封闭原则。所以一般适用于产品组合产品族变化不大的情况。
总结
上面介绍的三种工厂模式有各自的应用场景,实际应用时能解决问题满足需求即可,可灵活变通,无所谓高级与低级。
此外无论哪种模式,由于可能封装了大量对象和工厂创建,新加产品需要修改已定义好的工厂相关的类,因此对于产品和工厂的扩展不太友好,利弊需要权衡一下。
参考链接:https://www.cnblogs.com/yssjun/p/11102162.html
参考链接:https://blog.youkuaiyun.com/weixin_44277627/article/details/88067366