工厂模式

1、概述

核心

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

工厂模式满足的OOP原则:

  • 开闭原则:一个软件的实体应当对扩展开放,对修改关闭
  • 依赖倒置原则:要针对接口编程,不要针对实现编程
  • 迪米特法则:只与你直接的朋友通信,而避免和陌生人通信

三种模式:

  • 简单(静态)工厂模式
    • 用来生产同一等级结构中的任意产品(对于增加新的产品,需要扩展已有代码)
  • 工厂方法模式
    • 用来生产同一等级结构中的固定产品(支持增加任意产品)
  • 抽象工厂模式
    • 围绕一个超级工厂创建其他工厂。该超级工厂又成为其他工厂的工厂

应用场景:

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

2、简单(静态)工厂模式

工厂模式+抽象工厂模式_ide

  1. 编写Car接口类:Car.java

    package pers.mobian.factory;
    
    public interface Car {
        public void show();
    }
    
  2. 编写具体的汽车类,且该类是Car类的实现类:BenChi.java、AoDi.java

    package pers.mobian.factory;
    
    public class BenChi implements Car {
        @Override
        public void show() {
            System.out.println("我是奔驰汽车");
        }
    }
    
    package pers.mobian.factory;
    
    public class AoDi implements Car {
    
        @Override
        public void show() {
            System.out.println("我是奥迪汽车");
        }
    }
    
  3. 编写对应的汽车工厂类:FactoryCar.java

    package pers.mobian.factory;
    
    //静态工厂模式
    //增加一个新的产品,如果不修改代码,不好处理
    public class FactoryCar {
        //方法一:
        public static Car getCar(String car) {
            if (car.equals("奔驰")) {
                return new BenChi();
            } else if (car.equals("奥迪")) {
                return new AoDi();
            } else {
                return null;
            }
        }
    
    
        //方法二:
        public static Car getBenChi() {
            return new BenChi();
        }
    
        public static Car getAoDi() {
            return new AoDi();
        }
    }
    
  4. 编写具体的实现类:FactoryTest01.java

    package pers.mobian.factory;
    
    public class FactoryTest01 {
        public static void main(String[] args) {
    
            //传统的调用方式
            Car car0 = new BenChi();
            car0.show();
            Car car1 = new BenChi();
            car1.show();
    
            System.out.println("======");
    
            //简单工厂类的两种不同实现方式
            Car car2 = FactoryCar.getCar("奔驰");
            Car car3 = FactoryCar.getCar("奥迪");
            car2.show();
            car3.show();
            System.out.println("-----");
            Car car4 = FactoryCar.getAoDi();
            Car car5 = FactoryCar.getBenChi();
            car4.show();
            car5.show();
        }
    }
    
  5. 测试结果

    我是奔驰汽车
    我是奔驰汽车
    ======
    我是奔驰汽车
    我是奥迪汽车
    -----
    我是奥迪汽车
    我是奔驰汽车
    

总结:此方式可以避免了直接new对象,但是一但需要添加汽车类,势必会新增代码,继而不满足OOP的开闭原则,所以引入了工厂方法模式。


3、工厂方法模式

工厂模式+抽象工厂模式_ide_02

  1. 编写汽车类和汽车工厂类的接口Car.java、CarFactory.java

    package pers.mobian.factory.method;
    
    public interface Car {
        public void show();
    }
    
    package pers.mobian.factory.method;
    
    public interface CarFactory {
        public Car getCar();
    }
    
  2. 编写具体的汽车类,且该类是Car类的实现类:BenChi.java、AoDi.java

    package pers.mobian.factory.method;
    
    public class AoDi implements Car {
    
        @Override
        public void show() {
            System.out.println("我是奥迪汽车");
        }
    }
    
    package pers.mobian.factory.method;
    
    public class BenChi implements Car {
        @Override
        public void show() {
            System.out.println("我是奔驰汽车");
        }
    }
    
  3. 编写对应的汽车工厂类,并且该类是工厂类接口的实现类:AoDiFactory.java、BenChiFactory.java

    package pers.mobian.factory.method;
    
    public class BenChiFactory implements CarFactory{
        @Override
        public Car getCar() {
            return new BenChi();
        }
    }
    
    package pers.mobian.factory.method;
    
    public class AoDiFactory implements CarFactory {
        @Override
        public Car getCar() {
            return new AoDi();
        }
    }
    
  4. 编写具体的实现类:FactoryTest02.java

    package pers.mobian.factory.method;
    
    public class FactoryTest02 {
        public static void main(String[] args) {
            Car car1 = new BenChiFactory().getCar();
            car1.show();
    
            Car car2 = new AoDiFactory().getCar();
            car2.show();
        }
    }
    
  5. 测试结果

    我是奔驰汽车
    我是奥迪汽车
    

总结:工厂方法模式在不修改原有代码的基础上,可以更加灵活的添加功能。即同时满足没有直接new对象,也符合开闭原则。但却会出现另一个问题,即增加的类会很多,并且如果在Car类中包含很多的具体实现,就会导致接口过于庞大。继而引入抽象工厂模式。


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

  • 结构复杂度:抽象工厂模式更简单
  • 代码复杂度:抽象工厂模式更简单
  • 编程复杂度:抽象工厂模式更简单
  • 管理上的复杂度;抽象工厂模式更简单

结论:根据设计原则使用工厂方法模式更好,根据实际业务,往往更多的采用简单工厂模式。


抽象工厂模式

5、抽象工厂模式

抽象工厂模式与工厂模式都属于23种设计模式中的创建者模式之一

定义

抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类

适用场景

  • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
  • 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的重复代码
  • 提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现

优点

  • 具体产品在应用层的代码隔离,无需关心创建的细节
  • 将一个系列的产品统一到一起创建

缺点

  • 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难
  • 增加了系统的抽象性和理解难度

工厂模式+抽象工厂模式_其他_03

  1. 编写三个接口类:RouteProduct.java、PhoneProduct.java、ProductFactory.java

    package pers.mobian.factory.abstract1;
    
    public interface RouteProduct {
        public void statr();
        public void close();
        public void wifi();
        public void set();
    }
    
    package pers.mobian.factory.abstract1;
    
    public interface PhoneProduct {
        public void start();
        public void close();
        public void call();
        public void send();
    }
    
    package pers.mobian.factory.abstract1;
    
    public interface ProductFactory {
        PhoneProduct phoneProduct();
        RouteProduct routeProduct();
    }
    
  2. 编写PhoneProduct接口类的实现类:XiaomiPhone.java、HuaweiPhone.java

    package pers.mobian.factory.abstract1;
    
    public class XiaomiPhone implements PhoneProduct {
        @Override
        public void start() {
            System.out.println("小米手机可以开机");
        }
    
        @Override
        public void close() {
            System.out.println("小米手机可以关机");
        }
    
        @Override
        public void call() {
            System.out.println("小米手机可以打电话");
        }
    
        @Override
        public void send() {
            System.out.println("小米手机可以发短信");
        }
    }
    
    package pers.mobian.factory.abstract1;
    
    public class HuaweiPhone implements PhoneProduct {
        @Override
        public void start() {
            System.out.println("华为手机可以开机");
        }
    
        @Override
        public void close() {
            System.out.println("华为手机可以关机");
        }
    
        @Override
        public void call() {
            System.out.println("华为手机可以打电话");
        }
    
        @Override
        public void send() {
            System.out.println("华为手机可以发短信");
        }
    }
    
  3. 编写RouteProduct接口类的实现类:XiaomiRoute.java、HuaweiRoute.java

    package pers.mobian.factory.abstract1;
    
    public class XiaomiRoute implements RouteProduct {
        @Override
        public void statr() {
            System.out.println("小米路由器可以开机");
        }
    
        @Override
        public void close() {
            System.out.println("小米路由器可以关机");
        }
    
        @Override
        public void wifi() {
            System.out.println("小米路由器可以打开wifi");
        }
    
        @Override
        public void set() {
            System.out.println("小米路由器可以设置");
        }
    }
    
    package pers.mobian.factory.abstract1;
    
    public class HuaweiRoute implements RouteProduct {
        @Override
        public void statr() {
            System.out.println("华为路由器可以开机");
        }
    
        @Override
        public void close() {
            System.out.println("华为路由器可以关机");
        }
    
        @Override
        public void wifi() {
            System.out.println("华为路由器可以打开wifi");
        }
    
        @Override
        public void set() {
            System.out.println("华为路由器可以设置");
        }
    }
    
  4. 编写ProductFactory接口类的实现类:XiaomiFactory.java、HuaweiFactory.java

    package pers.mobian.factory.abstract1;
    
    public class XiaomiFactory implements ProductFactory {
        @Override
        public PhoneProduct phoneProduct() {
            return new XiaomiPhone();
        }
    
        @Override
        public RouteProduct routeProduct() {
            return new XiaomiRoute();
        }
    }
    
    package pers.mobian.factory.abstract1;
    
    public class HuaweiFactory implements ProductFactory {
        @Override
        public PhoneProduct phoneProduct() {
            return new HuaweiPhone();
        }
    
        @Override
        public RouteProduct routeProduct() {
            return new HuaweiRoute();
        }
    }
    

    5、编写具体的实现类:FactoryTest03.java

    package pers.mobian.factory.abstract1;
    
    public class FactoryTest03 {
        public static void main(String[] args) {
            System.out.println("========小米生产线========");
            XiaomiFactory xiaomiFactory = new XiaomiFactory();
            PhoneProduct phoneProduct = xiaomiFactory.phoneProduct();
            phoneProduct.call();
            RouteProduct routeProduct = xiaomiFactory.routeProduct();
            routeProduct.wifi();
    
            System.out.println("========华为生产线========");
            HuaweiFactory huaweiFactory = new HuaweiFactory();
            PhoneProduct phoneProduct1 = huaweiFactory.phoneProduct();
            phoneProduct1.close();
            RouteProduct routeProduct1 = huaweiFactory.routeProduct();
            routeProduct1.set();
    
        }
    }
    

    测试结果:

    ========小米生产线========
    小米手机可以打电话
    小米路由器可以打开wifi
    ========华为生产线========
    华为手机可以关机
    华为路由器可以设置
    

总结:

想要实现某一个功能,只需要关注其工厂类,不需要关注其实现细节。当新增加功能的时候,如生产笔记本,只需要它们各自去实现其笔记本接口,再在抽象工厂类中添加相应的产品即可完成需求。但是,当在抽象工厂类中添加产品的过程 中,就违反了开闭原则。但如果这种改变如果以后是长期稳定的,也是可以进行适当的违反的。