原创

设计模式详解(零)——简单工厂模式


前言

简单工厂模式不是一个标准的设计模式,也并不属于23种设计模式中的任何一种,但是它是抽象工厂模式工厂方法模式的基础,且在日常工作中非常常见,姑且作为学习其他设计模式的热身吧。

文章讲解思路:设计模式本质就是一个解决方案。因此在后续的设计模式系列文章中,博主会首先给大家引出一个场景问题,并使用传统的面向过程编程方式解决,通过分析传统方案的弊端,并使用指定的设计模式进行优化改进,从而加深大家对设计模式及其设计理念的理解。同时也适当对设计模式进行扩展,剖析开源框架中的设计模式应用。(Java)

一、场景问题

目前市场手机品牌琳琅满目,包括华为、苹果、小米、vivo等。假设某厂家可以生产华为、苹果、小米这三种品牌的手机,请设计出一种厂家根据客户要求某品牌手机的解决方案。

二、解决方案

1、传统解决方案

1.1、代码实现

  • 首先定义出产品的抽象接口

    public interface Phone {
        /**
         * 产品描述
         */
        void desc();
    }
    
  • 根据接口定义出三种产品的原型,代码很简单。

    //苹果手机
    public class ApplePhone implements Phone{
        @Override
        public void desc() {
            System.out.println("我是苹果手机");
        }
    }
    
    //华为手机
    public class HwPhone implements Phone{
        @Override
        public void desc() {
            System.out.println("我是华为手机");
        }
    }
    
    //小米手机
    public class MiPhone implements Phone{
        @Override
        public void desc() {
            System.out.println("我是小米手机");
        }
    }
    
  • 传统解决方案根据根据客户不同的需求,创建不同的手机实例,可以将用户的需求设置为参数传递,根据参数的不同创建不同的手机实例,代码也很简单

    public class Client {
        public static void main(String[] args) {
            String phoneType = "huawei";
            Phone phone = null;
            //根据不同的类型创建不同的手机实例
            if ("apple".equals(phoneType)) {
                phone = new ApplePhone();
            } else if ("xiaomi".equals(phoneType)) {
                phone = new MiPhone();
            } else if ("huawei".equals(phoneType)) {
                phone = new HwPhone();
            } else {
                throw new RuntimeException("不支持的手机品牌");
            }
            phone.desc();
        }
    }
    

1.2、传统方式实现的优缺点

  • 优点:实现简单,代码易读。这也是博主小白刚入门能写出的代码,典型的面向过程编程。

  • 缺点

    • 违反开闭原则

      即软件实体应当对扩展开放,对修改关闭。怎么理解呢?当厂家想新增vivo品牌手机的生产线时,这时候就需要在原来的基础上再添加一个else if分支来,本身修改代码并不是特别麻烦的事,麻烦的事是在我们需要修改所有订购手机的代码。

    • 暴露实例细节

      客户端可以清晰知道什么牌子的手机对应的实例实现,这样导致自己的内部细节暴露给了客户端。

2、简单工厂模式方案

知道了传统方式的弊端,那么解决方案也就好想了。我们也将创建手机实例的功能交给一个工厂类来执行,客户端只负责传递自己的需求,由工厂类来返回具体的手机实例。

2.1、代码实现

  • 定义创建手机实例的工厂类,负责手机的生产

    public class PhoneFactory {
        public static Phone newPhoneInstance(String phoneType) {
            //根据不同的类型创建不同的手机实例
            if ("apple".equals(phoneType)) {
                return new ApplePhone();
            } else if ("xiaomi".equals(phoneType)) {
                return new MiPhone();
            } else if ("huawei".equals(phoneType)) {
                return new HwPhone();
            } else {
                throw new RuntimeException("不支持的手机品牌");
            }
        }
    }
    
  • 那么客户端代码可以修改为

    public static void main(String[] args) {
            String phoneType = "huawei";
            //利用工厂类创建手机实例
            Phone phone = PhoneFactory.newPhoneInstance(phoneType);
            phone.desc();
        }
    

2.2、方案解析

根据上面的代码我们可以看到,我们定义了一个工厂类,客户端直接调用工厂类的静态方法获取手机实例,工厂类根据客户的传递参数返回具体的实现类。这样一方面对客户端隐藏了实现类细节,客户端只知道手机的接口,无法知道具体是哪一个实现类;另一方面所有生产手机都可以调用该处逻辑,后续如果添加手机品牌也只需要修改一处即可。

三、模式剖析

经过上次的案例分析,大家应该对简单工厂模式有个大概的认识,接下来我们从该模式本身进行全面剖析。

1、模式定义

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例被创建的实例通常都具有共同的父类

2、模式结构

简单工厂模式一般包含如下角色

  • Factory工厂角色

    工厂角色负责实现创建所有实例的内部逻辑

  • Product抽象产品角色

    抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口(也可以是抽象类)

  • ConcreteProduct具体产品角色

    抽象产品角色的实现类

3、模式结构图

4、优缺点

  • 优点
    • 工厂类负责实例的创建细节,且对客户端隐藏,清晰划分责任,专门的类做专门的事。
    • 一定程度上提高系统的灵活性扩展性。扩展产品时主要添加产品实现类、修改工厂类逻辑,客户端无需修改,只需要修改传递参数即可完成。
  • 缺点
    • 由于工厂类负责了整个系统的产品创建,所以一旦工厂类出问题,会影响到整个系统
    • 每增加一个产品就会增加一个产品的实现类,一定程度上增加系统的复杂性
    • 工厂类的频繁修改。每次添加一个产品就需要修改工厂类。当产品数量过多时,会导致创建产品的逻辑过于复杂,不利于维护。
    • 简单工厂模式一般使用静态工厂形式,造成工厂角色无法形成基于继承的等级结构

5、使用场景

  • 如果想要对客户端隐藏对象创建的细节完全封装隔离具体的实现,可以考虑使用。
  • 集中管理对象的创建(这些对象可以相关、也可以不相关)。目的实现集中管理和控制
Java
设计模式
  • 作者:贤子磊
  • 发表时间:2021-05-16 06:30
  • 版权声明:自由转载-非商用-非衍生-保持署名
  • 评论

    您需要登录后才可以评论