zoukankan      html  css  js  c++  java
  • 简单工厂模式和工厂方法模式

    文章首发于我的个人博客,欢迎访问:https://blog.itzhouq.cn/factory

    工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 Java里边共有23种设计模式而工厂模式就有三种,它们分别是简单工厂模式(并不在23中模式之中),工厂方法模式以及抽象工厂模式,其中我们通常所说的工厂模式指的是工厂方法模式,工厂方法模式是日常开发中使用频率最高的一种设计模式。

    在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

    1、介绍

    意图: 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

    主要解决: 主要解决接口选择的问题。

    何时使用: 我们明确地计划不同条件下创建不同实例时。

    如何解决: 让其子类实现工厂接口,返回的也是一个抽象的产品。

    关键代码: 创建过程在其子类执行。

    应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。

    优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

    缺点: 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

    使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

    注意事项: 作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

    2、简单工厂模式

    简单工厂模式实现

    使用简单的例子说明什么是简单工厂模式。

    假设现在有不同种类的车,消费者可以自行选择消费某种车。如果按照以前的思路是将车作为一个接口,不同的车实现这个接口,消费时,创建一个实现类,将车接口指向实现类。代码如下:

    创建一个车的接口:

    public interface Car {
        void getName();
    }
    

    创建一个实现类,比如五菱宏光

    public class Wuling implements Car {
        @Override
        public void getName() {
            System.out.println("五菱宏光");
        }
    }
    

    再创建一个实现类,比如特斯拉

    public class Tesla implements Car {
        @Override
        public void getName() {
            System.out.println("特斯拉");
        }
    }
    

    现在模拟消费车的过程,比如我们需要买一辆五菱宏光,再买一辆特斯拉,来一个测试类:

    public class FactoryTest {
        public static void main(String[] args) {
            Car car = new Wuling();
            Car car2 = new Tesla();
    
            car.getName(); // 五菱宏光
            car2.getName(); // 特斯拉
        }
    }
    

    可以看到我们每次消费车的时候都需要使用new关键词来创建车对象。这其实是有问题。对于消费者来说,我不关心车是怎么造出来的,我只需要知道车的名称就好了,但是这里消费者需要知道车的结构,创建车对象需要哪些参数。这里的车对象创建的时候使用了无参构造器,实际的情况可能复杂一些。

    为了解决这个问题我们可以引入一个工厂类,这个工厂类目的是制造各种车。消费者消费的时候直接根据车的名称从工厂中拿即可,不需要知道车的结构,不需要自己new对象。

    public class CarFactory {
        public static Car getCar(String car) {
            if ("五菱宏光".equalsIgnoreCase(car)) {
                return new Wuling();
            } else if ("特斯拉".equalsIgnoreCase(car)) {
                return new Tesla();
            } else {
                return null;
            }
        }
    }
    

    现在再次模拟消费的过程:

    public class FactoryTest {
        public static void main(String[] args) {
    //        Car car = new Wuling();
    //        Car car2 = new Tesla();
            // 使用工厂创建
            Car car = CarFactory.getCar("五菱宏光");
            Car car2 = CarFactory.getCar("特斯拉");
    
            car.getName(); // 五菱宏光
            car2.getName(); // 特斯拉
        }
    }
    

    这样简单工厂模式就实现了。

    简单工厂模式的核心本质:

    • 实例化对象不需要new,用工程方法代替
    • 将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

    简单工厂模式的问题

    现在有一个需求:消费者需要购买大众牌的车。对于这个需求,我们需要修改新引入一个类Dazhong,实现Car接口,然后修改工厂类。

    public class Dazhong implements Car {
        @Override
        public void getName() {
            System.out.println("大众");
        }
    }
    

    修改工厂:

    public class CarFactory {
        public static Car getCar(String car) {
            if ("五菱宏光".equalsIgnoreCase(car)) {
                return new Wuling();
            } else if ("特斯拉".equalsIgnoreCase(car)) {
                return new Tesla();
            } else if ("大众".equalsIgnoreCase(car)) {
                return new Dazhong();
            } else {
                return null;
            }
        }
    }
    

    添加了一个新的判断。消费的方式没有变化。

    从设计的角度讲,简单工厂模式是不符合开闭原则。增加了一个新的产品,需要修改原来的代码。所以简单工厂模式也叫静态工厂模式

    下面使用示意图分析一下简单工厂模式。

    简单工厂模式

    为了解决简单工程模式的问题,我们引入工厂方法模式。

    3、工厂方法模式

    工厂方法模式是简单工厂的进一步深化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。

    车接口不变:

    public interface Car {
        void getName();
    }
    

    引入一个车的工厂接口,所有具体的车工厂都要实现这个接口:

    public interface CarFactory {
        Car getCar();
    }
    

    五菱宏光:五菱宏光车工厂和实现类:

    public class WulingFactory implements CarFactory {
        @Override
        public Car getCar() {
            return new Wuling();
        }
    }
    
    public class Wuling implements Car {
        @Override
        public void getName() {
            System.out.println("五菱宏光");
        }
    }
    

    特斯拉:特斯拉工厂和实现类:

    public class TeslaFactory implements CarFactory {
        @Override
        public Car getCar() {
            return new Tesla();
        }
    }
    
    public class Tesla implements Car {
        @Override
        public void getName() {
            System.out.println("特斯拉");
        }
    }
    

    模拟消费:

    public class Consumer {
        public static void main(String[] args) {
            Car car = new WulingFactory().getCar();
            Car car2 = new TeslaFactory().getCar();
    
            car.getName(); // 五菱宏光
            car2.getName(); // 特斯拉
        }
    }
    

    这就是工程方法模式,符合开闭原则。

    对于需求,不需要修改现有的工厂类,而是增加一个对应的车工厂和实现类。比如,现在增加了一个摩拜车。

    那我先写一个摩拜车类:

    public class Mobai implements Car {
        @Override
        public void getName() {
            System.out.println("摩拜");
        }
    }
    

    再写一个摩拜车工厂:

    public class MobaiFactory implements CarFactory {
        @Override
        public Car getCar() {
            return new Mobai();
        }
    }
    

    消费者消费这个车的车的时候,不需要修改CarFactory,直接使用摩拜车工厂创建摩拜车。

    public class Consumer {
        public static void main(String[] args) {
            Car car = new WulingFactory().getCar();
            Car car2 = new TeslaFactory().getCar();
            Car car3 = new MobaiFactory().getCar();
    
            car.getName(); // 五菱宏光
            car2.getName(); // 特斯拉
            car3.getName(); // 摩拜
        }
    }
    

    和简单工厂对比一下,最根本的区别在于,简单工厂只有一个统一的工厂类,而工厂方法是针对每个要创建的对象都会提供一个工厂类,这些工厂类都实现了一个工厂基类(本例中的CarFactory )。

    示意图:

    工厂方法模式

    4、比较简单工厂模式和工厂方法模式

    从设计原则比如开闭原则来看,工厂方法模式更好。但是从结构复杂度、代码复杂度、编程复杂度、管理复杂度上来说,简单工厂模式更方便,实际使用得更多。

    5、工厂模式的应用场景

    • JDK 中 Calendar 的 getInstance 方法
    • JDBC 中 Connection 对象的获取
    • Spring 中的 IOC 容器创建管理 bean对象
    • 反射中 Class对象的 newInstance 方法。

    参考文章1

    参考文章2

  • 相关阅读:
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_14-课程预览功能开发-CMS添加页面接口
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_13-课程预览功能开发-CMS页面预览接口测试
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_12-课程预览功能开发-需求分析
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_11-课程详情页面静态化-课程信息模板设计
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_10-课程详情页面静态化-课程详情模型数据查询接口
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_09-课程详情页面静态化-静态页面测试
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_08-课程预览技术方案
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_07-Feign远程调用-Feign测试
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_06-Feign远程调用-Ribbon测试
    阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_05-Feign远程调用-客户端负载均衡介绍
  • 原文地址:https://www.cnblogs.com/itzhouq/p/factory.html
Copyright © 2011-2022 走看看