设计模式之工厂模式

本文深入介绍了工厂模式在Java中的应用,包括简单工厂模式、工厂方法模式和抽象工厂模式。简单工厂模式适用于产品较少的情况,但职责过重;工厂方法模式解决了扩展问题,每个产品对应一个专门的工厂;抽象工厂模式则用于创建一系列相关产品,但扩展性较差。通过案例展示了三种模式的实现和优缺点。
摘要由CSDN通过智能技术生成

工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

工厂模式的实现有三种:简单工厂模式、工厂方法模式、抽象工厂模式

一、简单工厂模式

简单工厂模式不属于GoF的23种设计模式。

简单工厂模式是指由一个工厂对象决定创建哪一种产品类的实例,适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象不需要关心。

假设一个场景,有一个汽车工厂,可以生产各类汽车,如宝马、奔驰、特斯拉等

// 产品接口,汽车类的抽象
public interface Car {
    public void produce();
}
// 具体产品类,宝马类
public class Bmw implements Car {
    @Override
    public void produce() {
        System.out.println("宝马出厂!");
    }
}
// 具体产品类,奔驰类
public class Benz implements Car {
    @Override
    public void produce() {
        System.out.println("奔驰出厂!");
    }
}
// 通过反射实现汽车工厂
public class CarFactory {
	// 传入需要创建的对象的类
    public Car create(Class<? extends Car> clazz) {
        try {
            if (clazz != null) {
                // 返回类的实例
                return clazz.newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
// 简单工厂模式客户端测试
public class Test {
    public static void main(String[] args) {
        CarFactory factory = new CarFactory();
        // 需要什么类就通过工厂创建什么类
        Car car = factory.create(Benz.class);
        car.produce();
    }
}

看上去和在客户端直接new Benz()的结果差不多,但是事实上如果采用new去创建对象的话,客户端就会直接依赖于产品类(Bmw类、Benz类),当产品类越来越多的时候,客户端中的依赖也会越来越臃肿,我们需要减弱这些依赖,将创建对象的细节隐藏起来,通过一个工厂就可以创建所需要的产品类的对象,创建对象的过程不需要放在客户端当中。

但是简单工厂模式有个缺点就是工厂类的职责过重,不易于扩展过于复杂的产品类。

二、工厂方法模式

工厂方法模式是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法模式将类的实例化推迟到子类中进行,在工厂方法模式中用户只需要关心所需产品对应的工厂,不需要关心创建细节。

工厂方法模式主要解决产品扩展的问题,在简单工厂模式中,随着产品链的丰富,如果每类汽车的创建逻辑有区别,则工厂的职责会变得越来越多,更像一个万能工厂,但是难以维护。所以根据单一职责原则将工厂进行拆分,让一个工厂干专门的事,比如Bmw只让Bmw工厂生产,Benz只让Benz工厂生产。

场景和上面的场景一样,Car接口、Bmw类、Benz类不变

// 对工厂类进行抽象,作为一个工厂接口
public interface CarFactory {
    public Car create();
}

// Bmw工厂
public class BmwFactory implements CarFactory{
    
    // 除了创建Bmw类外可以进行一些Bmw工厂特有的操作,在create()方法中也可以进行特有操作
    
    @Override
    public Car create() {
        return new Bmw();
    }
}
// Benz工厂
public class BenzFactory implements CarFactory {
    
    // 除了创建Bmw类外可以进行一些Benz工厂特有的操作,在create()方法中也可以进行特有操作
    
    @Override
    public Car create() {
        return new Benz();
    }
}
// 客户端测试
public class Test {
    public static void main(String[] args) {
        CarFactory factory = new BmwFactory();
        Car car = factory.create();
        car.produce();

        factory = new BenzFactory();
        car = factory.create();
        car.produce();
    }
}

使用工厂方法模式在客户端测试的时候看上去是比简单工厂模式复杂了,对于每一个产品类都要创建一个工厂去完成对象的创建,但是相比于简单工厂模式,在工厂方法模式的工厂中可以针对于每一类产品去做一些特有的操作而不影响其他的工厂,但是使用工厂方法模式会造成类的个数容易过多,增加了系统的抽象性和理解难度。

三、抽象工厂模式

抽象工厂模式是指提供一个创建一系列相关或相互依赖对象的接口,无需指定它们的具体类。客户端(应用层)不依赖于产品类实例如何被创建、如何被实现等细节,强调的是一系列相关的产品对象(属于统一产品族)一起使用创建对象需要大量重复的代码,需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

首先要了解两个概念:产品族和产品等级结构。

我们来假设一个场景:

美的生产很多家用电器:空调、冰箱、洗衣机等

格力也生产这些电器: 空调、冰箱、洗衣机等

海尔也生成这些电器: 空调、冰箱、洗衣机等

那么【空调、冰箱、洗衣机等】就是一个产品族,【美的的空调、格力的空调、海尔的空调】就是一个产品等级结构。

此外美的电器由美的工厂生产,格力电器由格力工厂生产,海尔电器由海尔工厂生产等等。

接着我们就这个场景实现抽象工厂模式。

// 我们有两个产品(用两个产品做例子就够了):空调和冰箱
// 空调
public interface AirCondition {
    public void cold();
}
// 我们有两个产品(用两个产品做例子就够了):空调和冰箱
// 冰箱
public interface Refrigerator {
    public void ice();
}
// 创建一个抽象工厂类
public interface ApplianceFactory {
    // 生产空调和冰箱
    AirCondition createAirCondition();
    Refrigerator createRefrigerator();
}
// 创建美的产品族的空调类
public class MediaAirCondition implements AirCondition {
    @Override
    public void cold() {
        System.out.println("美的空调制冷");
    }
}
// 创建美的产品族的冰箱类
public class MediaRefrigerator implements Refrigerator {
    @Override
    public void ice() {
        System.out.println("美的冰箱冷藏");
    }
}
// 创建美的产品族的具体工厂
public class MediaFactory implements ApplianceFactory {
    @Override
    public AirCondition createAirCondition() {
        return new MediaAirCondition();
    }

    @Override
    public Refrigerator createRefrigerator() {
        return new MediaRefrigerator();
    }
}
// 格力产品族的空调类
public class GreedyAirCondition implements AirCondition {
    @Override
    public void cold() {
        System.out.println("格力空调制冷");
    }
}
// 格力产品族的冰箱类
public class GreedyRefrigerator implements Refrigerator {
    @Override
    public void ice() {
        System.out.println("格力冰箱冷藏");
    }
}
// 格力工厂
public class GreedyFactory implements ApplianceFactory {
    @Override
    public AirCondition createAirCondition() {
        return new GreedyAirCondition();
    }

    @Override
    public Refrigerator createRefrigerator() {
        return new GreedyRefrigerator();
    }
}
// 客户端测试
public class Test {
    public static void main(String[] args) {
        ApplianceFactory factory = new MediaFactory();
        factory.createAirCondition().cold();
        factory.createRefrigerator().ice();

        factory = new GreedyFactory();
        factory.createAirCondition().cold();
        factory.createRefrigerator().ice();

    }
}

通过这个例子可以看出抽象工厂模式中其实有用到工厂方法模式,但是相比于工厂方法模式,抽象工厂模式子类可以生产一系列相关的产品,而工厂方法模式子类更加倾向于决定生产什么产品。

但是抽象工厂方法模式缺点很明显,如果我们再增加一个产品洗衣机,那么从抽象工厂开始所有的类都要进行调整,难以维护,并且抽象工厂模式增加了系统的抽象性和理解难度。

参考文章:
《SPRING5 核心原理和30个类手写实战》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值