设计模式(一)-工厂模式


简叙

对于工厂模式大家肯定不陌生,但实际要你明白的把工厂模式讲清楚你还真不一定能很清楚的讲出来。总的来说工厂模式从简单到复杂大体上可以分为以下几种:

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

而在我们常说的设计模式简单工厂模式并不在23种设计模式中,而这三种模式都归结在创建模式中。简单的说工厂模式所要解决的问题就是让客户端创建对象时变得简单(这里的客户端通常指的是调用者)。可能大多数情况下我们创建对象就是new一下便可完成,但某些情况下想要创建一个对象并不是什么简单的事。例如在JDK中创建线程池,因为创建线程池时我们需要设置线程池大小、等待时间、缓冲队列等等一系列参数,所以JDK为我们提供了Executors用来简化创建线程池。而这种将构建对象的逻辑提供方法出来让客户端调用,不仅可以让客户端构建对象变得简单,而且一旦构建对象的逻辑发生了变化也不需要客户端去修改代码,只需要修改创建方法即可。

简单工厂模式

简单工厂模式也叫静态工厂方法模式,它通过一个工厂对象决定创建出哪一种产品类的实例,简单的说就是将对象的创建逻辑隐藏在工厂对象中,使用者只需要调用工厂方法,传入简单的参数便可以创建出对象。简单工厂模式一般包含三种对象:

工厂角色

对于所有的实际产品都由该对象负责创建

public class VehicleFactory {

    /**
     * 创建交通工具
     * @param type 交通工具类型
     * @return
     */

    public static Vehicle create(String type){
        if (Objects.equals("公交车",type)){
            return new Bus();
        }else if (Objects.equals("自行车",type)){
            return new Bicycle();
        }else if (Objects.equals("小汽车",type)){
            return new Car();
        }else {
            throw new RuntimeException("不支持的类型");
        }
    }
}

抽象产品

对工厂中要生产的产品的抽象

public interface Vehicle {
    /**
     * 打印名称
     */

    void printName();
}

具体产品

实际工厂中生产的产品

public class Bicycle implements Vehicle{

    @Override
    public void printName() {
        System.out.println("自行车");
    }
}

public class Bus implements Vehicle{

    @Override
    public void printName() {
        System.out.println("公交车");
    }
}

public class Car implements Vehicle{

    @Override
    public void printName() {
        System.out.println("小汽车");
    }
}

客户端调用

而客户端创建产品实例时并不需要知道具体是何种类型,只需要传入简单的参数便可以构建出具体的产品实例。

public class App {
    public static void main(String[] args) {
        Vehicle car = VehicleFactory.create("小汽车");
        car.printName();

        Vehicle bus = VehicleFactory.create("公交车");
        bus.printName();
    }
}

但是该模式存在一个明显的缺陷,如果我新增一种产品类型我需要修改工厂对象的内容逻辑。如果产品越来越多会导致工厂方法内部逻辑变得更加复杂难以维护,对于扩展性而言也并不是那么友好。

设计模式(一)-工厂模式
简单工厂UML

工厂方法模式

通过上面的简单工厂模式我们明白一点,随着实际产品数量的增加会导致工厂方法内部变得复杂,同时最致命的点在于每次产品的新增都将导致工厂内部代码的修改。而我们现在要介绍的工厂方法模式对于上面的情况会得到部分改善,它通过抽象工厂的方式使得即使产品增加,我们也不需要去修改原有的工厂方法,同时也使得工厂内部方法变得更加清晰。

抽象工厂

将原本创建产品的工厂抽象出来,而不同的产品则通过不同的工厂来生产。

public interface IVehicleFactory {
    /**
     * 创建交通工具
     * @return
     */

    Vehicle create();
}

具体工厂

将简单工厂模式中创建产品的逻辑提取到具体的工厂中。

public class BicycleFactory implements IVehicleFactory{

    @Override
    public Vehicle create() {
        return new Bicycle();
    }
}

public class BusFactory implements IVehicleFactory{

    @Override
    public Vehicle create() {
        return new Bus();
    }
}

public class CarFactory implements IVehicleFactory{

    @Override
    public Vehicle create() {
        return new Car();
    }
}

客户端调用

public class App {
    public static void main(String[] args) {
        IVehicleFactory factory = new BusFactory();
        Vehicle bus = factory.create();
        bus.printName();

        factory = new CarFactory();
        Vehicle car = factory.create();
        car.printName();
    }
}

扩展新的产品

如果现在增加新的产品Truck,我们只需要新增一个创建Truck的工厂实现即可。

public class Truck implements Vehicle {
    @Override
    public void printName() {
        System.out.println("卡车");
    }
}

public class TruckFactory implements IVehicleFactory{
    @Override
    public Vehicle create() {
        return new Truck();
    }
}

存在的问题

工厂方法模式和简单工厂模式虽然都是通过工厂来创建对象,但是他们之间最大的区别在于工厂方法模式在设计上完全完全符合“开闭原则。对于新产品的新增,我们并不需要去修改原有的工厂内部逻辑。但是工厂方法模式并不是完美的,如果随着产品的增加我们实际生产产品的工厂也需要对应的增加,这在一定程度上使得系统中类的数量增多。

设计模式(一)-工厂模式
工厂方法UML

抽象工厂模式

抽象工厂与工厂方法不同的点在于,抽象工厂提供创建一系列对象的接口。例如现在我们需要开发一个客户端应用,考虑到用户电脑硬件的性能存在差异。对于电脑硬件比较差的用户我们在UI方面需要简化一些,保证用户能正常使用。而对于电脑性能较好的用户,我们可以将UI设置得漂亮一点,使用户能享受到更好的使用体验。如果我们还是使用工厂方法模式来设计代码,可以想象到这将会产生许多的工厂类,这时候抽象工厂就能发挥出它的优点了。

抽象工厂

这里的抽象工厂提供了生产一系列对象的方法,例如UI组件中的按钮(button)、菜单(menu)等等。

public interface IUiComponentFactory {
    /**
     * 创建按钮
     * @return
     */

    Button createButton();

    /**
     * 创建菜单
     * @return
     */

    Menu createMenu();
}

抽象产品

抽象出UI组件中的按钮和菜单

public interface Button {
    /**
     * 展示样式
     */

    void showStyle();
}

public interface Menu {

    /**
     * 展示样式
     */

    void showStyle();
}

具体产品

定义出简单和漂亮的组件产品

public class SimpleButton implements Button{
    @Override
    public void showStyle() {
        System.out.println("简单样式按钮");
    }
}

public class SimpleMenu implements Menu{
    @Override
    public void showStyle() {
        System.out.println("简单样式菜单");
    }
}

public class BeautifulButton implements Button{
    @Override
    public void showStyle() {
        System.out.println("漂亮的菜单");
    }
}

public class BeautifulMenu implements Menu{
    @Override
    public void showStyle() {
        System.out.println("漂亮的菜单");
    }
}

具体工厂

实现抽象工厂接口,定义出能创建Simple和Beautiful类型的具体工厂

public class SimpleUiComponentFactory implements IUiComponentFactory{

    @Override
    public Button createButton() {
        return new SimpleButton();
    }

    @Override
    public Menu createMenu() {
        return new SimpleMenu();
    }
}

public class BeautifulUiComponentFactory implements IUiComponentFactory{

    @Override
    public Button createButton() {
        return new BeautifulButton();
    }

    @Override
    public Menu createMenu() {
        return new BeautifulMenu();
    }
}

客户端调用

public class App {
    
public static void main(String[] args) {
        System.out.println(
"用户电脑差使用简单UI");
        IUiComponentFactory factory = 
new SimpleUiComponentFactory();
        Button button = factory.createButton();
        button.showStyle();
        Menu menu = factory.createMenu();
        menu.showStyle();

        System.out.println(
"用户电脑好使用漂亮的UI");
        factory = 
new BeautifulUiComponentFactory();
        button = factory.createButton();
        button.showStyle();
        menu = factory.createMenu();
        menu.showStyle();
    }
}

分析

从上面客户端的调用代码可以发现,我们工厂创建UI组件都是类似的。例如工厂类型为SimpleUiComponentFactory时,则该工厂创建的组件全是Simple的,从这里面你们能感觉到抽象工厂像是工厂的工厂。从这里也能知道,工厂方法模式的一个工厂只能创建一个具体产品,而抽象工厂则可以创建属于同一类型的多种产品。而抽象工厂的缺点在于如果想支持新种类的产品,这将导致所有工厂都需要修改。例如我们现在增加一个Windows组件,这意味着抽象工厂接口需要新增生成Windows组件的方法,而所有的具体工厂也跟着需要一起修改。所以在使用抽象工厂时,最好能事先确定抽象工厂能生产的产品。

设计模式(一)-工厂模式
抽象工厂UML

总结

看到这里对于上面三种工厂模式你应该大致了解清楚了。

  • 简单工厂模式在主要就是屏蔽了产品创建的逻辑实现,调用者不需要关心内部如何实现,代码实现方面也比较简单。而它的缺点则体现在不符合开放-封闭原则。
  • 工厂方法模式则继承了简单工厂模式的优点,同时符合开放-封闭原则。即使后续需要新增产品,也不需要去修改之前的代码。而它的缺点则表现在随着产品的增多,对应的工厂类成对增多。
  • 抽象工厂每次可以通过具体工厂创建同类型的多个产品,如果新增一种类型的多个产品会十分方便。但它存在的缺点是抽象工厂新增产品则会导致开发-封闭原则被打破。

本文示例代码地址:https://gitee.com/zengchao_workspace/design-pattern


原文始发于微信公众号(一只菜鸟程序员):设计模式(一)-工厂模式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/72903.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!