设计模式之工厂设计模式

本文介绍了工厂设计模式的三种主要形式:简单工厂模式、工厂方法模式和抽象工厂模式。简单工厂模式通过一个工厂类创建所需对象,但添加新类型时需修改工厂类。工厂方法模式通过接口实现产品创建,允许添加新工厂而不修改原有代码,遵循开闭原则。抽象工厂模式则用于创建一族相关产品,提供了创建多个产品等级结构的接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工厂设计模式

实现了创建者和调用者分离。
分类:
      简单工厂模式
      工厂方法模式
      抽象工厂模式

核心本质:
      ① 实例化对象不使用new,用工厂方法代替。

      ② 将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

简单工厂模式

      再看简单工厂模式之前,我们先来看一看我们使用传统的方式创建对象是怎么来创建的。

      首先我们有一个Car接口,其实现类有Audi、BMW、Benz。我们想要这三个实现类的对象时,我们就需要使用new关键字。即:

// 给定一个Car接口
public interface Car {
   void name();
}

//Audi实现了Car接口,使其具有车的属性
public class Audi implements  Car{
    @Override
    public void name() {
        System.out.println("奥迪");
    }
}

//同理Benz
public class Benz implements Car {
    @Override
    public void name() {
        System.out.println("奔驰");
    }
}

//同理BMW
public class BMW implements Car {
    @Override
    public void name() {
        System.out.println("宝马");
    }
}

      此时,有一个消费者,他想要买一辆车,这个时候,我们传统的方式是去new一个车,即:

public class Consumer {
    public static void main(String[] args) {
        Car car1 = new Audi();
        Car car2 = new BMW();
        Car car3 = new Benz();
        car1.name();
        car2.name();
        car3.name();
        
    }
}

图示:
在这里插入图片描述

      这种传统的方式看起来无可厚非,我们想要什么车,就去new什么车就好了,但是,这种传统的方式相当于我们自己去"造车",如果我们调用Audi类的构造器去new时,这个构造器有多个参数,那么我们每去new一个实例时,都要往里面传多个参数。这样就会很麻烦。有没有一种方式,我们不用去关注如何创建的这个对象,就可以拿到这个对象呢?下来我们来看一看简单工厂方式。

      简单工厂模式,我们使用一个工厂类,这个工厂类帮助我们去创建我们想要的车的类型,我们只需要传入我们想要车的名字即可。
      该工厂类定义如下:

public class CarFactory {
    public static Car getCar(String name){
        if (name.equals("奥迪")){
            return new Audi();
        }else if(name.equals("奔驰")){
            return new Benz();
        }else if(name.equals("宝马")){
            return new BMW();
        }else{
            return null;
        }
    }
}

      我们看到,这个工厂根据我们传入的参数,可以创建出对应类的实例。此时,我们想要拿到某一个类的实例时,只需要传入对应的参数即可:

public class Consumer {
    public static void main(String[] args) {
        Car car1 = CarFactory.getCar("奥迪");
        Car car2 = CarFactory.getCar("奔驰");
        Car car3 = CarFactory.getCar("宝马");
        car1.name();
        car2.name();
        car3.name();
    }
}

      我们并没有自己去"造车",而是将造车的任务交给了CarFactory这个类,对于怎么造的车,对于我们消费者来说是不知道的,消费者只需要输入自己想要的车就行了。
在这里插入图片描述

      但是,这种方式也有缺点,我们是可以不用关心如何创建的实例,但是,如果我们想要一个新的类的实例时,就必须改动我们的工厂类的代码,这违反了我们的开闭原则。还是用这个例子举例,有一天突然来了个消费者,它不想要Audi,也不想要Benz,也不想要BMW,他就支持国产,他想买一辆哈佛,此时,我们就必须修改CarFactory的代码,并提供Haval类。(修改CarFactory代码违反了开闭原则)


public class Haval implements Car {
    @Override
    public void name() {
        System.out.println("哈佛");
    }
}

public class CarFactory {
    public static Car getCar(String name){
        if (name.equals("奥迪")){
            return new Audi();
        }else if(name.equals("奔驰")){
            return new Benz();
        }else if(name.equals("宝马")){
            return new BMW();
        }else if (name.equals("哈佛")){
            return new Haval();
        }else{
            return null;
        }
    }
}

      有没有一种形式,我们无需修改代码呢?接下来我们介绍工厂模式

工厂方法模式

      在前面,我们说到了简单工厂模式,也说到了它的缺点,而我们的工厂模式,则是简单工厂模式的改进版本。

      工厂模式中包含的角色:
                  ① 抽象工厂(Factory):在抽象工厂类中,声明了工厂方法,用于返回一个产品。所有创建对象的工厂类都必须实现该接口。

                  ② 具体工厂(ConcreteFactory):它是抽象工厂的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体的产品。

                  ③ 抽象产品(Product):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是所有产品的公共父类。

                  ④ 具体产品(ConcreteProduct):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间是 一 一 对应的关系。
      我们可以为每一个类型的车,都创建一个车工厂,即奥迪有自己的车间,奔驰有自己的车间等等。于是,我们将所有品牌的车的车间抽象出来,创建一个CarFactory接口,每个品牌的车都实现了CarFactory接口,表示其具有造车的功能:

// 车间
public interface CarFactory {
    Car getCar();
}

//奥迪车间
public class AudiFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new Audi();
    }
}

//奔驰车间
public class BenzFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new Benz();
    }
}

//宝马车间
public class BMWFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new BMW();
    }
}

//消费者
public class Consumer {
    public static void main(String[] args) {
        Car car1 = new BMWFactory().getCar();
        Car car2 = new AudiFactory().getCar();
        Car car3 = new BenzFactory().getCar();
    }
}

在这里插入图片描述

      相比较简单工厂模式来说,简单工厂是一个人去了一家工厂,这家工厂里面只有奥迪、奔驰、宝马这三种车,这个人只能在这三种车里面选,如果想选其他的车,这家工厂就得进行改进,去创建新的车。

      而工厂方法模式就好比,一个人去买车,我想买奥迪,我就去奥迪4S店,我想买奔驰,我就去奔驰4S店,我想买宝马,我就去宝马4S店,我想买哈佛,我就去哈佛4S店。这个时候就会有疑问了啊,这里明显没有HavalFactory,怎么去买哈佛啊?我们可以新创建一个HavalFactory呀,这里就是和简单工厂区分的一个点简单工厂模式如果想要添加新的功能,就必须修改工厂类里的代码,但是工厂方法模式不需要修改,注意我这里说的是修改原工厂类,在工厂方法模式中,我即使添加了一个HavalFactory和Haval类,我都没有修改原有工厂类里的代码

      细心地朋友可能注意到了,嗷,虽然你没有修改原有工厂类的代码,但是,你每多一个车,你就会多一个扩展类,这样非常麻烦。

抽象工厂模式

      正在工厂方法模式中,具体工厂负责生产具体的产品,每一个具体工厂对应一个具体产品,工厂方法具有唯一性。有时候,我们希望一个工厂可以提供多个产品对象。而不是单一的产品对象,如一个华为工厂,它可以生产华为手环、华为手机、华为路由器等多种设备,而不是只生产某一种设备。为了更好地理解抽象工厂模式,我们先引入两个概念:

            产品等级结构:产品等级即产品的继承结构,如一个抽象类是手机,其子类有华为手机,小米手机,苹果手机。则抽象类与具体品牌的手机之间构成了一个产品等级结构。
            产品族:在抽象工厂模式中,产品族指由一个工厂生产的,位于不同产品等级结构中的一组产品。如华为工厂生产了华为手机、华为路由器、华为手环,这些都是由华为工厂生产的,华为手机位于手机产品等级结构中,华为手环位于手环产品等级结构中,华为路由器位于路由器产品等级结构中。
在这里插入图片描述
            当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。

            抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式又称为Kit模式,是一种创建型模式。

            抽象工厂模式中包含几个角色:
                        AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每个方法对应一种产品。

                        ConcreteFactory(具体工厂):它实现了抽象工厂中声明的创建产品的方法,生产一组具有体产品,这些产品构成了一个产品族,每一个产品都位于不同的产品等级结构中

                        AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。

                        ConcreteProduct(具体产品):它定义了具体工厂生产的具体产品的对象,实现抽象产品接口中声明的方法。

            我们使用抽象工厂模式来构建产品的设计,其结构如下:
在这里插入图片描述
            其中Factory接口充当抽象工厂,其子类HuaWeiFactory、XiaoMiFactory充当具体工厂。接口PhoneProduct、RouterProduct充当抽象产品,其子类HuaWeiPhone、XiaoMiPhone、HuaWeiRouter、XiaoMiRouter充当具体产品。代码如下:

// 抽象工厂
public interface ProductFactory {
    // 生产手机
    IphoneProduct phoneProduct();

    // 生产路由器
    RouterProduct routerProduct();
}

// 具体工厂:华为工厂
public class HuaWeiFactory implements ProductFactory {
    @Override
    public IphoneProduct phoneProduct() {
        return new HuaWeiPhone();
    }

    @Override
    public RouterProduct routerProduct() {
        return new HuaWeiRouter();
    }
}

// 具体工厂:小米工厂
public class XiaoMiFactory implements ProductFactory {

    @Override
    public IphoneProduct phoneProduct() {
        return new XiaoMiPhone();
    }

    @Override
    public RouterProduct routerProduct() {
        return new XiaoMiRouter();
    }
}


// 抽象产品:手机
public interface IphoneProduct {
    void start();
    void shutdown();
    void call();
    // 发短信
    void sendMes();
}

// 具体手机产品:华为手机
public class HuaWeiPhone implements IphoneProduct {
    @Override
    public void start() {
        System.out.println("华为开机");
    }

    @Override
    public void shutdown() {
        System.out.println("华为手机关机");
    }

    @Override
    public void call() {
        System.out.println("华为手机打电话");
    }

    @Override
    public void sendMes() {
        System.out.println("华为手机发短信");
    }
}


//具体手机产品:小米手机
public class XiaoMiPhone implements IphoneProduct {
    @Override
    public void start() {
        System.out.println("小米手机开机");
    }

    @Override
    public void shutdown() {
        System.out.println("小米手机关机");
    }

    @Override
    public void call() {
        System.out.println("小米手机打电话");
    }

    @Override
    public void sendMes() {
        System.out.println("小米手机发短信");
    }
}

//抽象产品:路由器
public interface RouterProduct {
    void start();
    void shutdown();
    void openwifi();
}

//具体路由器产品:小米路由器
public class XiaoMiRouter implements RouterProduct {
    @Override
    public void start() {
        System.out.println("开启小米路由器");
    }

    @Override
    public void shutdown() {
        System.out.println("关闭小米路由器");
    }

    @Override
    public void openwifi() {
        System.out.println("开启小米wifi");
    }
}

// 具体路由器产品:华为路由器
public class HuaWeiRouter implements RouterProduct {
    @Override
    public void start() {
        System.out.println("开启华为路由器");
    }

    @Override
    public void shutdown() {
        System.out.println("关闭华为路由器");
    }

    @Override
    public void openwifi() {
        System.out.println("开启华为wifi");
    }
}

//验证:
public class Client {
    public static void main(String[] args) {
        //小米系列产品
        XiaoMiFactory xiaomifactory = new XiaoMiFactory();
        System.out.println("========小米系列产品=======");
        IphoneProduct xiaomiphone = xiaomifactory.phoneProduct();
        xiaomiphone.start();
        xiaomiphone.sendMes();
        RouterProduct xiaomirouter = xiaomifactory.routerProduct();
        xiaomirouter.start();
        xiaomirouter.openwifi();
        HuaWeiFactory huaweifactory = new HuaWeiFactory();
        System.out.println("========华为系列产品=======");
        IphoneProduct huaweiphone = huaweifactory.phoneProduct();
        huaweiphone.start();
        huaweiphone.sendMes();
        RouterProduct huaweirouter = huaweifactory.routerProduct();
        huaweirouter.start();
        huaweirouter.openwifi();
    }
}

            其输出结果为:
在这里插入图片描述
            抽象工厂模式的优点:
                        ① 具体产品在应用层的代码隔离,无需关心创建的细节。
                        ② 将一个系列的产品统一到一起创建。

            抽象工厂模式的缺点:
                        ① 如果我们想要新增加一个具体的产品,就必须修改抽象工厂里的代码。比如:我们想生产一个具体的产品:笔记本,我们就需要在抽象工厂里添加一个创建笔记本的方法,然后让具体工厂实现这个方法,显然这违反了“开闭原则”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值