java设计模式-工厂模式(上)

什么是工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。通过使用工厂模式,可以将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象。

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

工厂模式可以分为三类:简单工厂模式(静态工厂模式)、工厂方法模式 和 抽象工厂模式。

其中简单工厂模式,严格上来说,不属于23设计模式之一,因为它违背了开闭原则,更好的是看作为一种编程方式。

本篇中会介绍三种工厂的使用,也就是

  • 简单(静态)工厂模式(不属于GOF的23种经典设计模式)
  • 工厂方法模式
  • 抽象工厂模式

使用场景

日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

等等。。。

下面我们模拟手机工厂生产手机。。。

核心角色

  • 抽象产品:定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。
  • 具体产品:实现了抽象产品接口,定义了具体产品的特定行为和属性。
  • 抽象工厂:声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
  • 具体工厂:实现了抽象工厂接口,负责实际创建具体产品的对象。

1.简单(静态)工厂模式

实现了抽象工厂接口,负责实际创建具体产品的对象。

结构

简单工厂包含如下角色:

  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品:实现或者继承抽象产品的子类
  • 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品。

示例

模拟手机工厂生产手机。

我们需要定义一个抽象手机产品,定义手机产品的品牌和颜色两个方法

/**
 * 手机产品抽象类
 *
 * @author jiangkd
 * @date 2023/7/28 14:03:15
 */
public abstract class AbstractPhone {

    /**
     * 手机品牌
     */
    public abstract void brand();

    /**
     * 手机颜色
     */
    public abstract void color();

}

然后有两个具体产品,一加和真我,哈哈哈

/**
 * 具体手机产品, 一加手机
 *
 * @author jiangkd
 * @date 2023/7/28 14:06:17
 */
@Slf4j
public class YijiaPhone extends AbstractPhone {

    @Override
    public void brand() {
        log.info("品牌, 一加手机!!!");
    }

    @Override
    public void color() {
        log.info("黑色!!!");
    }
    
}
/**
 * 具体手机产品, 真我手机
 *
 * @author jiangkd
 * @date 2023/7/28 14:07:27
 */
@Slf4j
public class ZhenwoPhobe extends AbstractPhone {

    @Override
    public void brand() {
        log.info("品牌, 真我手机!!!");
    }

    @Override
    public void color() {
        log.info("白色!!!");
    }

}

产品有了,现在我们创建一个手机工厂,可以根据不同参数创建不同品牌手机

/**
 * 手机产品的工厂
 *
 * @author jiangkd
 * @date 2023/7/28 14:09:50
 */
public class PhoneFactory {

    /**
     * 具体如何产生一个产品的对象,是由具体的工厂类实现的
     * 

* 注意, 这里是静态方法 * * @param clazz * @return AbstractPhone * @throws Exception e */ public static AbstractPhone createPhone(Class clazz) throws Exception { // 全限定类名 final String name = clazz.getName(); // 根据反射, 创建具体产品对象 return (AbstractPhone) Class.forName(name).newInstance(); } /** * 当前方法其实和createPhone方法是一样的作用, 两个方法用哪个都可以 *

* 注意, 这里是静态方法 * * @param brand 根据参数区分创建哪个具体产品 * @return AbstractPhone */ public static AbstractPhone createPhone2(String brand) throws Exception { if (CharSequenceUtil.equals("yijia", brand)) { return new YijiaPhone(); } else if (CharSequenceUtil.equals("zhenwo", brand)) { return new ZhenwoPhobe(); } else { throw new Exception("参数异常!!!"); } } }

测试一下

/**
 * @author jiangkd
 * @date 2023/7/28 14:17:25
 */
@Slf4j
public class DemoTest {

    public static void main(String[] args) throws Exception {

        // 创建一加手机
        AbstractPhone yijiaPhone = PhoneFactory.createPhone(YijiaPhone.class);
        yijiaPhone.brand();
        yijiaPhone.color();

        log.info("--------------------------------");

        yijiaPhone = PhoneFactory.createPhone2("yijia");
        yijiaPhone.brand();
        yijiaPhone.color();

        log.info("--------------------------------");

        // 创建真我手机
        AbstractPhone zhenwoPhone = PhoneFactory.createPhone(ZhenwoPhobe.class);
        zhenwoPhone.brand();
        zhenwoPhone.color();

        log.info("--------------------------------");

        zhenwoPhone = PhoneFactory.createPhone2("zhenwo");
        zhenwoPhone.brand();
        zhenwoPhone.color();

    }

}

运行结果如下:

14:19:59.846 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 品牌, 一加手机!!!
14:19:59.851 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 黑色!!!
14:19:59.851 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.DemoTest - --------------------------------
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 品牌, 一加手机!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 黑色!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.DemoTest - --------------------------------
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 白色!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.DemoTest - --------------------------------
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 白色!!!

其实可以看出来,这里我们只有两个具体的手机产品,简答(静态)工厂模式还是很方便的,但你有没有发现,如果现在我陆陆续续追加其他具体产品 红米!努比亚!荣耀!那么我就要陆陆续续三次修改手机工厂类(追加具体产品不算修改,是扩展功能)的功能,这显然不符合java设计模式的六大原则-开闭原则。

那不如我们把工厂拆开,每个工厂只生产一种具体的手机产品,这样如果我需要增加一个红米,就只需要添加一个红米工厂和一个红米产品类就可以了,这就是接下来要演示的工厂方法模式

2.工厂方法模式

简单工厂模式确实很方便,但是每次新增一个手机产品都需要改动整个工厂的原有代码,现在使用工厂方法模式改造一下。

抽象手机产品AbstractPhone 和 两个具体的手机产品(一加,真我)不变,依然如上。

工厂类PhoneFactory不要了,我们需要重新创建工厂类。

现在我们首先创建一个抽象工厂类,用来生产AbstractPhone

/**
 * 定义产品的抽象工厂类
 *
 * @author jiangkd
 * @date 2023/7/28 14:43:04
 */
public abstract class AbstractPhoneFactory {

    /**
     * 构建产品, 具体实现交给子类
     *
     * @return AbstractPhone
     */
    abstract AbstractPhone createPhone();

}

然后分别是一加手机和真我手机的两个具体工厂实现类,每个实现类针对一个具体手机品牌的生产

/**
 * 具体产品一加手机的工厂实现类
 *
 * @author jiangkd
 * @date 2023/7/28 14:44:53
 */
public class YijiaPhoneFactory extends AbstractPhoneFactory {

    @Override
    AbstractPhone createPhone() {
        return new YijiaPhone();
    }

}
/**
 * 具体产品真我手机的工厂实现类
 *
 * @author jiangkd
 * @date 2023/7/28 14:45:35
 */
public class ZhenwoPhoneFactory extends AbstractPhoneFactory {

    @Override
    AbstractPhone createPhone() {
        return new ZhenwoPhobe();
    }

}

测试一下

/**
 * @author jiangkd
 * @date 2023/7/28 14:46:16
 */
@Slf4j
public class DemoTest {

    public static void main(String[] args) {

        // 生产一加手机
        final AbstractPhoneFactory yijiaPhoneFactory = new YijiaPhoneFactory();
        final AbstractPhone yijiaPhone = yijiaPhoneFactory.createPhone();

        yijiaPhone.brand();
        yijiaPhone.color();

        log.info("--------------------------------");

        // 生产真我手机
        final AbstractPhoneFactory zhenwoPhoneFactory = new ZhenwoPhoneFactory();
        final AbstractPhone zhenwoPhone = zhenwoPhoneFactory.createPhone();

        zhenwoPhone.brand();
        zhenwoPhone.color();

    }

}

运行结果如下:

14:48:22.596 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 品牌, 一加手机!!!
14:48:22.598 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 黑色!!!
14:48:22.598 [main] INFO demo.basic.example.design_patterns.gcms.gcffms.DemoTest - --------------------------------
14:48:22.599 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:48:22.599 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 白色!!!

现在我们如果想要加一个红米手机,只需要创建具体红米产品和对应的工厂类就可以了

/**
 * 具体手机产品 红米
 *
 * @author jiangkd
 * @date 2023/7/28 14:51:09
 */
@Slf4j
public class HongmiPhone extends AbstractPhone {

    @Override
    public void brand() {
        log.info("品牌, 红米手机!!!");
    }

    @Override
    public void color() {
        log.info("红色!!!");
    }
    
}
/**
 * 红米手机工厂实现类
 *
 * @author jiangkd
 * @date 2023/7/28 14:52:04
 */
public class HongmiPhoneFactory extends AbstractPhoneFactory {

    @Override
    AbstractPhone createPhone() {
        return new HongmiPhone();
    }

}

测试

/**
 * @author jiangkd
 * @date 2023/7/28 14:46:16
 */
@Slf4j
public class DemoTest {

    public static void main(String[] args) {

        // 生产一加手机
        final AbstractPhoneFactory yijiaPhoneFactory = new YijiaPhoneFactory();
        final AbstractPhone yijiaPhone = yijiaPhoneFactory.createPhone();

        yijiaPhone.brand();
        yijiaPhone.color();

        log.info("--------------------------------");

        // 生产真我手机
        final AbstractPhoneFactory zhenwoPhoneFactory = new ZhenwoPhoneFactory();
        final AbstractPhone zhenwoPhone = zhenwoPhoneFactory.createPhone();

        zhenwoPhone.brand();
        zhenwoPhone.color();

        log.info("--------------------------------");

        // 生产红米手机
        final AbstractPhoneFactory hongmiPhoneFactory = new HongmiPhoneFactory();
        final AbstractPhone hongmiPhone = hongmiPhoneFactory.createPhone();

        hongmiPhone.brand();
        hongmiPhone.color();

    }

}

执行结果

14:53:43.272 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 品牌, 一加手机!!!
14:53:43.274 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 黑色!!!
14:53:43.274 [main] INFO demo.basic.example.design_patterns.gcms.gcffms.DemoTest - --------------------------------
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 白色!!!
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.gcffms.DemoTest - --------------------------------
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.HongmiPhone - 品牌, 红米手机!!!
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.HongmiPhone - 红色!!!

符合开闭原则,不修改原来的功能,只是添加产品和工厂类就可以了。

细心的小伙伴又会问了,虽然不用在原基础功能上修改,但是如果还要添加10个品牌手机,岂不是要加10个产品类和10个工厂类,增加维护难度呀!是的,这就是工厂方法模式的弊端,增加系统的复杂度。

所以你可以看出,简单(静态)工厂和工厂方法模式,都是针对一类产品的生产,也就是这些工厂只生产同种类产品,同种类产品称为同等级产品。(工厂方法模式只考虑生产同等级的产品)

但实际上呢,现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。

这就是下面的抽象工厂模式了。。。,我们继续延申,现在老板发话了,生产手机的时候,顺便把耳机也生产出来吧

3.抽象工厂模式

由于篇幅问题,继续查看java设计模式-工厂模式(下)

你可能感兴趣的:(java,#,设计模式,java,设计模式,开发语言)