【设计模式】二、工厂模式(10分钟搞定)

本文详细介绍了工厂模式的三种形式:简单工厂模式、工厂方法模式和抽象工厂模式。通过实例展示了如何逐步优化代码,提高可扩展性。简单工厂模式通过工厂类集中管理对象创建;工厂方法模式将创建过程交给具体的子类实现,遵循职责单一原则;抽象工厂模式则用于处理产品族和等级结构,提供更灵活的扩展。文章强调了工厂模式在减少重复代码、隔离客户端与产品实现细节方面的优势,并讨论了其潜在的缺点和适用场景。
摘要由CSDN通过智能技术生成

前言

工厂就是生产各种各样东西的地方,在代码中,就是创建一个个类。对于简单的类而言,我们直接new一个。但是对于一系列对象,或者对象创建需要很多额外的操作,我们需要集中的管理起来。比如new的时候需要初始化各种各样的参数、或者要调用很多其他的方法等等。我们每次new这个对象,都会重复做这么多繁琐的操作。久了会让人恶心头晕。现在我们要升华一下我们的代码。

一、简单工厂模式

举个栗子🌰:当我们需要水果这个对象,水果有苹果、香蕉、草莓、葡萄…等等对象的时候。

// 原来我们需要这么写
Apple apple = new Apple();
Banana banana = new Banana();

现在我们把生产水果封装到一个工厂中。
苹果香蕉都属于水果,所以我们需要一个水果的接口

/**
 * 水果类
 */
public interface Fruits {
    /**
     * 获取名称
     * @return
     */
    void getName();
}

苹果香蕉对应的实现该接口

public class AppleFruits implements Fruits {

    public void getName() {
        System.out.println("苹果");
    }
}
public class BananaFruits implements Fruits {

    @Override
    public void getName() {
        System.out.println("香蕉");
    }
}

1、工厂类

public class FruitsFactory {
    public Fruits create(String name){
        if("apple".equals(name)){
            return new AppleFruits();
        }else if("banana".equals(name)){
            return new BananaFruits();
        }else {
            return null;
        }
    }
}

这样我们在使用的时候,完全不用关心 AppleFruits,BananaFruits 这些具体得水果。

 FruitsFactory factory = new FruitsFactory();
 Fruits fruits = factory.create("apple");
 fruits.getName();

但是这样如果我们要新增一种水果,就要修改FruitsFactory类,多加一个if..else,这明显是不符合开闭原则的。所以我们可以升级一下。修改我们的工厂类。

2、优化工厂

    public Fruits create(String className){
        try {
            if (!(null == className || "".equals(className))) {
                return (Fruits) Class.forName(className).newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

这样我们在使用的时候只需要填写对应的类名。

 FruitsFactory factory = new FruitsFactory();
 Fruits fruits = factory.create("com.machuxin.AppleFruits");
 fruits.getName();

好处:新增水果的时候,不需要修改工厂类FruitsFactory
缺点:com.machuxin.AppleFruits 这个长的参数是什么鬼??

3、再优化工厂

public Fruits create(Class<? extends Fruits> clazz) {
        try {
            if (null != clazz) {
                return clazz.newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

这样我们填写参数的时候,只要对应的class即可。

        FruitsFactory factory = new FruitsFactory();
        Fruits fruits = factory.create(AppleFruits.class);
        fruits.getName();

这样参数不存在拼写的错误。后期拓展只需要对应的class实现Fruits 类即可。

在这里插入图片描述

二、工厂方法模式

当水果越来越多,水果工厂就会越来越臃肿,什么水果都能生产,成了万能水果厂。这样不符合职责单一原则。我们希望苹果工厂只生产苹果、香蕉工厂只生产香蕉。于是对工厂进行抽象。

/**
 * 工厂模型
 */
public interface FruitsFactory {

    Fruits create();

}
/**
 * 苹果厂只生产苹果
 */
public class AppleFactory implements FruitsFactory {

    public Fruits create() {
        return new AppleFruits();
    }
}
/**
 * 香蕉厂只生产香蕉
 */
public class BananaFactory implements FruitsFactory {

    public Fruits create() {
        return new BananaFruits();
    }
}

测试使用

    public static void main(String[] args) {
        FruitsFactory factory = new AppleFactory();
        Fruits fruits = factory.create();
        fruits.getName();

        factory = new BananaFactory();
        fruits = factory.create();
        fruits.getName();
    }

在这里插入图片描述工厂模式适合场景:

  1. 创建对象需要大量重复代码
  2. 客户端(应用层) 不依赖与产品实例如何创建、实现等细节
  3. 通过自类来决定创建那个对象

缺点:
1、类的个数多,复杂度高。
2、增加系统的抽象性,理解难度高

三、抽象工厂

随着产品的种类越来越多,产品的等级越来越高。为方便统一整理,便出现了抽象工厂。我们先来梳理一下产品族与等级。
在这里插入图片描述
水果分为苹果、香蕉、葡萄。同样苹果也分为A级苹果(红苹果)、B级苹果(青苹果)、C类苹果(紫苹果)
于是我们的工厂将可想横向、纵向,两个方向进行可扩展。

public abstract class AbstractFruitsFactory {

    protected abstract IColor color();

    protected abstract ISize size();
}

水果有颜色还有大小两个方法。

/**
 * 颜色
 */
public interface IColor {

    void getColor();
}

/**
 * 大小
 */
public interface ISize {

    void getSize();
}

苹果工厂继承抽象工厂,实现大小与颜色2个接口。

public class AppleFactory extends AbstractFruitsFactory {
    
    @Override
    protected IColor color() {
        return new AppleColor();
    }

    @Override
    protected ISize size() {
        return new AppleSize();
    }
}

苹果大小接口

public class AppleSize implements ISize {

    @Override
    public void getSize() {
        System.out.println("1斤");
    }
}

苹果颜色接口

public class AppleColor implements IColor{

    @Override
    public void getColor() {
        System.out.println("红色");
    }
}

使用实例

        AppleFactory factory = new AppleFactory();
        factory.color().getColor();
        factory.size().getSize();

在这里插入图片描述
如果所示,我们通过继承AbstractFruitsFactory 对水果产品种类实现了横向扩展,同时,对IColorISize等接口的实现提供了纵向的扩展。

缺点:如果要增加纵向功能,如重量,需要对AbstractFruitsFactory 接口进行修改。这不符合我们的开闭原则。但实际生活中,这是一件比较正常的事,只要修改不频繁,我们是可以容忍的。还好JAVA8 提供default 关键字,允许父类采用默认实现。改动量大大减小了。

至此,工厂模式已经完成了,如果有理解不到位的地方,欢迎大家指教。
源码地址:https://gitee.com/xiaowangz/learning-note

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值