目录
1、什么是工厂模式
2、为什么要用工厂模式
3、简单工厂模式
4、工厂方法模式
5、抽象工厂模式
前言:本文简要介绍了工厂模式,其中包含了23种设计模式中的“工厂方法模式”和“抽象工厂模式”。
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
我们先来看一个例子:
以下是咖啡接口和它的两个实现类:
public interface Coffee { //咖啡接口
}
public class LatteCoffee implements Coffee{ //拿铁咖啡实现类
}
public class AmericaCoffee implements Coffee { //美式咖啡实现类
}
我们有一个业务如下:根据用户的需求来给用户相应的咖啡,那么关键代码如下:
String str;//用户需求的咖啡
if(str.equals("LatteCoffee")){
return new LatteCoffee();
}else if (str.equals("AmericaCoffee")){
return new AmericaCoffee();
}
大家乍一看是不是感觉没什么问题,但是如果我此时加一个“卡布奇诺咖啡”呢?是不是我们要去修改源代码?是不是就违反了我们软件设计原则中的“开闭原则”?而且如果我这一段代码在很多程序中都需要使用,是不是我就要修改无数个地方的代码,不仅麻烦而且可能会一不小心就修改错代码了。不仅如此,如果我们真这样写代码的话,“耦合性”可就太大了!以上就是为什么我们要用工厂设计模式的原因。
(这里有一种解耦的搭配方式:简单工厂模式+配置文件,这种搭配能达到不用修改原代码,当有类变更时,只需要修改配置文件即可,大家感兴趣可以去搜一下,本文不详细讲解)
那么,工厂设计模式有哪几种呢?可以粗略分为以下几种:①简单工厂模式 ②工厂方法模式 ③抽象工厂模式。
简单工厂模式不属于23大设计模式之一,因此与其说是一种设计模式,不如说是一种好的开发习惯,它主要就是利用了“封装”的思想,把我们以上创建各种“coffee”的工作交给了“工厂类”,而不是直接的在我们程序中来创建:
public class CoffeFactory {
public Coffee createCoffee(String type){ //创建客户需要的咖啡
if(type.equals("LatteCoffee"))return new LatteCoffee();
if(type.equals("AmericaCoffee"))return new AmericaCoffee();
return null;
}
}
可见,如果我们使用简单工厂,我们以后如果想加入某个咖啡后,并不需要去修改我们所有用到咖啡的程序中的逻辑,只需要修改CoffeeFactory类里的createCoffee()方法的逻辑即可,大大降低了我们程序的耦合度。
因此,简单工厂的优点如下:
封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
但大家可以注意到:我们上述优点中说了无需修改原代码,只需要修改工厂类,是不是还是不满足我们的“开闭原则”,那么如何解决这个问题呢?这就需要用到我们接下来说的“工厂方法模式”。
我们仅需将以上“CoffeeFactory”的代码变为如下:
public abstract class CoffeeFactory { //抽象咖啡工厂
public abstract Coffee createCoffee();//创建客户需要的咖啡
}
然后加入两个它的实现类:
public class AmericaCoffeeFactory extends CoffeeFactory {
@Override
public Coffee createCoffee() {
return new AmericaCoffee();
}
}
public class LatteCoffeeFactory extends CoffeeFactory {
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
}
此时,我们创建咖啡时,只需要将对应的工厂类赋值给对应变量即可,代码如下:
public class CoffeeStore {
CoffeeFactory factory;
public CoffeeStore(CoffeeFactory coffeeFactory){
this.factory=coffeeFactory;
}
public Coffee createCoffee(){
return factory.createCoffee();
}
}
此时,我们只需要在“卖咖啡”的时候,告诉程序我们需要哪个咖啡工厂,即可得到对应的咖啡。这样屏蔽了内部创建咖啡的过程。而且最大的优点是如果此时我们想修改咖啡的种类,比如我们多加入一个“卡布奇诺”咖啡,我们只需要新创建一个卡布奇诺的咖啡类和对应的咖啡工厂即可,完美符合“开闭原则”。
因此工厂方法模式的优点如下:
不仅继承了简单工厂模式的所有优点(解耦,创建过程与使用过程分离开来,不会相互干扰),还解决了简单工厂模式不符合“开闭原则”的缺点。
但是,工厂方法模式真的“无懈可击”了吗?不!大家在仔细思考后会发现:虽然我们解决了开闭原则的问题,但是依然存在以下问题:
①如果咖啡种类很多,那我们是不是就要创建很多个“咖啡类”和很多个“咖啡工厂类”,是不是就会发生“类爆炸”。
②这种模式仅能创建一种产品,如果我们此时需要多个产品呢?
针对以上第二个问题,我们有了一个更高级的模式:“抽象工厂模式”。
在说抽象工厂模式前,我们先来看一个图片:
同一级别:同一个类型的产品,如苹果手机和华为手机就是同一级别。
同一产品族:同一个产商生产的产品,如苹果手机和苹果电脑就是同一产品族。
我们的“工厂方法模式”,仅仅能产生一个产品, 而我们的“抽象工厂模式”可以说是其的一种升级,它能产生同一产品族的多个产品,比如我们上述代码的咖啡工厂(“CoffeeFactory”)只能生产咖啡,而此时如果我们用抽象工厂模式,可以让它除了“Coffee”外还可以生产“Dessert”(甜点)之类的。代码如下:
public abstract class CoffeeFactory { //抽象咖啡工厂
public abstract Coffee createCoffee();//创建客户需要的咖啡
public abstract Dessert createDessert();//创建客户需要的咖啡
}
public class LatteCoffeeFactory extends CoffeeFactory {
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
@Override
public Dessert createDessert() {
return new LatteDessert();
}
}
public class AmericaCoffeeFactory extends CoffeeFactory {
@Override
public Coffee createCoffee() {
return new AmericaCoffee();
}
@Override
public Dessert createDessert() {
return new AmericaDessert();
}
}
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
使用场景:
当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空
调等。
系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结
构。
如:输入法换皮肤,一整套一起换。生成不同操作系统的程序。