在Java设计模式中,工厂模式分为三种,分别为:
a.简单工厂模式
b.工厂方法模式
c.抽象工厂模式
这三种模式均属于设计模式中的创建性模式。但是,有的时候我们又会看到23种Java设计模式中仅含有工厂方法模式(上述的简单工厂模式、工厂方法模式合并)和抽象工厂模式。在我们刚刚学习设计模式的时候,这三种模式总是很容易混淆,或者说不清楚,在这篇文章中,我们会结合代码来很好的解释一下。
1.简单工厂模式:
简单工厂模式是三种方法中最简单的一种,又叫做静态工厂方法(Static Factory Method)模式简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式。在简单工厂模式中,我们会用到以下三种组件:
a.抽象的产品接口
b.具体实现的产品类
c.具实现工厂类
下面我们来看一个例子,这个例子的UML图如下(UML图绘制不太标准)
我们的目的就是创建一个CarFactory,创建不同品牌的Car
package Component;
/**
* Created by YanMing on 2017/3/21.
*/
public interface Car {
void sayBrand();
}
package Component;
/**
* Created by YanMing on 2017/3/21.
*/
public class Benz implements Car {
@Override
public void sayBrand() {
System.out.println("One Benz Car");
}
}
Ford 和 Toyota代码与Benz类似
package SimpleFactory;
/**
* Created by YanMing on 2017/3/21.
*/
public enum CarType {
Benz,
Ford,
Toyata
}
package SimpleFactory;
import Component.Benz;
import Component.Car;
import Component.Ford;
import Component.Toyota;
/**
* Created by YanMing on 2017/3/21.
*/
public class CarFactory {
public Car getCarByName(CarType carType) {
Car car;
switch (carType) {
case Benz:
car = new Benz();
break;
case Ford:
car = new Ford();
break;
case Toyata:
car = new Toyota();
break;
default:
car = null;
break;
}
return car;
}
}
至此,一个简单的工厂模式就全部完成了,你可以用下面的代码来测试一下:
package SimpleFactory;
import Component.Car;
/**
* Created by YanMing on 2017/3/21.
*/
public class SimpleFactoryTest {
public static void main(String [] args){
CarFactory carFactory = new CarFactory();
Car iToyota = carFactory.getCarByName(CarType.Toyata);
iToyota.sayBrand();
}
}
在简单工厂中,客户端只负责消费他所需要的类,换句话说,就是我们针对输入的选择放在了工厂方法里面。工厂方法根据客户端的输入来选择生成(Switch)。
简单工厂优缺点如下:
优点:工厂中包含了必要的逻辑判断,根据客户端的选择动态的实例化对象对于客户端来说,去除了具体产品的依赖。
缺点:当我们需要增加一个功能的时候,必须修改工厂原有类中的分支条件,这样我们不仅开放了扩展,还开放了修改。违背了开放封闭原则。
*开放-封闭原则其核心的思想是:软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
2.工厂方法模式:
工厂方法模式Factory Method,又称多态性工厂模式。定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类中。实现了开放-封闭原则。在工厂方法模式中,我们会用到一下四种组件:
a.抽象产品的接口
b.具体实现的产品类
c.抽象工厂的接口
d.具体实现的工厂类
我们继续修改CarFactory例子。保持Car接口及其实现不变,我们添加ICarFactory接口:
package Factory;
import Component.Car;
/**
* Created by YanMing on 2017/3/21.
*/
public interface ICarFactory {
Car createOneCar();
}
BenzFactory实现ICarFactory
package Factory;
import Component.Benz;
import Component.Car;
/**
* Created by YanMing on 2017/3/21.
*/
public class BenzFactory implements ICarFactory {
@Override
public Car createOneCar() {
return new Benz();
}
}
同理,FordFactory和ToyotaFactory代码类似。
我们编写一个测试用例:
package Factory;
import Component.Car;
/**
* Created by YanMing on 2017/3/21.
*/
public class FactoryTest {
public static void main(String args[]){
ICarFactory benzFactory = new BenzFactory();
Car iBenz = benzFactory.createOneCar();
iBenz.sayBrand();
}
}
在这种情况下,我们是在客户端来选择究竟生成什么。也就是说,我们将简单工厂中的判断逻辑拿到了客户端来。当我们需要添加一个产品功能的时候,添加一个新的产品类,然后添加一个相应实现工厂接口的工厂类。
工厂方法的优缺点:
优点:克服了简单工厂违背开放-封闭原则的缺点,同时实现了简单工厂模式封装对象创建的特点。
缺点:每次添加一个功能就会产生一个相应的工厂类,增大开发量。
3.抽象工厂方法:
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂方法提供了创建一系列相关或者 相互依赖对象的接口,而且无需指定他们的具体类。我们的抽象工程方法需要以下四个组件:
a.抽象产品的接口
b.具体实现的产品类
c.抽象工厂的接口
d.具体实现的工厂类
下面我们继续对CarFactory的例子修改。我们假如每个车需要一个车座,我们需要添加一个新的Seat类同时修改ICarFactory接口定义:
Seat接口定义:
package Component;
/**
* Created by YanMing on 2017/3/21.
*/
public interface Seat {
void sayMaterials();
}
修改后的ICarFactory:
package AbstractFactory;
import Component.Car;
import Component.Seat;
/**
* Created by YanMing on 2017/3/21.
*/
public interface ICarFactory {
Car createOneCar();
Seat createOneSeat();
}
BenzFactory定义:
package AbstractFactory;
import Component.Benz;
import Component.Car;
import Component.LeatherSeat;
import Component.Seat;
import Factory.*;
/**
* Created by YanMing on 2017/3/21.
*/
public class BenzFacory implements ICarFactory {
@Override
public Car createOneCar() {
return new Benz();
}
@Override
public Seat createOneSeat() {
return new LeatherSeat();
}
}
你会发现,工厂方法模式,是我们一个有抽象产品类,派生出多个具体产品类。利用一个抽象工厂类,派生出多个具体工厂类。每个具体工厂类只能创建一个具体产品类的实例。 抽象工厂模式,是我们有多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。利用一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类可以创建多个具体产品类的实例。
抽象工厂优缺点:
优点:抽象工厂模式隔离了具体类的生产,使得客户并不需要知道什么被创建。同时由于一个具体工厂生产的是一系列的产品族,产品族中的多个对象被设计成一起工作,它能保证客户端始终只使用同一个产品族中的对象。
增加新的具体工厂和产品族很方便,符合“开闭原则”。同时,符合依赖倒转原则。实现了针对接口编程。
缺点:新增功能改动量较大。
*依赖倒转原则:A.高层不应该依赖底层模块,两个都应该依赖抽象
B.抽象不应该依赖细节,细节应该依赖抽象。
P.S.文章不妥之处还望指正