为什么要用工厂模式?

解答这个问题前,我们先来了解什么是工厂模式。

工厂模式其实也称创建模式,是用于创建对象的一种方式。本质上就是用工厂方法来代替new实例化对象。

举个例子:我们在编写代码的时候,在一个A类中通过new的方式实例化了类B,那么A类和B类之间就存在耦合,如果以后修改了B类的代码和使用方式,例如需要在构造函数中传入参数,那么A类也就需要跟着修改了,一个类的依赖可能影响不大,但若有多个类依赖了B类,那么这个工作量将会相当的大,这无疑是件非常痛苦的事。这种情况下,我们需要把创建实例的工作单独分离,与调用方解耦,也就是使用工厂方法创建实例的工作封装起来。这样我们在需要调用对象的时候就不需要关心那些复杂的实例化问题。

工厂模式

工厂模式可分为两类:简单工厂模式和工厂模式。

简单工厂模式

定义一个接口和实现类,建立一个工厂类这些实现类进行实例的创建。

我们用球来举例,定义一个基本的接口Ball,和一个抽象方法Play (玩),

public interface Ball {
    void play();
}

创建一个篮球的类和一个足球的类,并实现该接口,

public class BasketBall implements Ball {
    public void play() {
        System.out.println("打篮球~~~");
    }
}
public class FootBall implements Ball {
    public void play() {
        System.out.println("踢足球~~~");
    }
}

然后,创建一个工厂类,可以用于生产篮球或者足球,

public class BallFactory {

    public Ball produce(String type) {
        if ("basketball".equals(type)) {
            return new BasketBall();
        } else if ("football".equals(type)) {
            return new FootBall();
        }
        return null;
    }
}

工厂类建好以后,我们就可以实例化工厂类,并调用 produce 方法来创建对应的实例对象,

public static void main(String[] args) {
    BallFactory factory = new BallFactory();
    Ball ball = factory.produce("basketball");
    ball.play();
}

结果输出:打篮球~~~

这就是简单工厂模式的基本实现,用关系图来表示就是:
设计模式:工厂模式,解除耦合的利器-LMLPHP
这种模式的优点是代码简单,能够根据具体的参数返回对应的实例对象。

当然缺点也很明显,就是工厂类集中了所有实例的创建逻辑,如果增加业务就要多出相应的工厂方法,不仅代码可能变得臃肿,也容易违反GRASPR的高内聚的责任分配原则

工厂模式

又称多态性工厂模式,是对简单工厂模式的改进。工厂模式中,一个子类对应一个工厂类,这些工厂类都实现了一个工厂接口。这相当于把一个简单工厂类拆分成多个工厂,这样代码就不会都耦合在同一个类里了。

具体的产品接口和实现类还是复用上面的代码,我们只需关注工厂方法的逻辑即可,

先创建一个工厂的接口

public interface IFactory {
    void produce();
}

然后创建对应业务的工厂类

public class BasketFactory implements IFactory {
    public Ball produce() {
        return new BasketBall();
    }
}
public class FootFactory implements IFactory {
    public Ball produce() {
        return new FootBall();
    }
}

测试代码

public static void main(String[] args) {
    BasketFactory basketFactory = new BasketFactory();
    Ball basket = basketFactory.produce();
    FootFactory footFactory = new FootFactory();
    Ball foot = footFactory.produce();
    basket.play();
    foot.play();
}

输出结果是:

打篮球~~~
踢足球~~

如上所示,如果需要添加新的产品,如排球,我们就多写一个工厂类即可,这样就不会把所有的业务都耦合到一个工厂类中了,用关系图表示如下:

最后,总结一下工厂模式的优点吧,

1、良好的封装性,代码结构清晰,调用者只需知道产品的类名即可,不需要知道创建对象的过程,降低代码间的耦合。

2、扩展性优秀,如果增加一个产品类,只需增加一个对应的工厂类。

3、屏蔽产品类。产品类的实现如何变化,调用者都不需要关心,只需关心产品的接口,只要接口保持不变,系统中的上层模块就不会发生变化。

4、工厂模式是典型的解耦框架,高层模块只需要知道产品的抽象类,其他的实现类都不需要关心,符合迪米特法则,符合依赖倒置原则,符合里氏替换原则。

参考:

《设计模式之禅》

07-10 11:53