01.【设计模式】工厂模式

一、前言

工厂模式由来:在显示生活中,原始生活自给自足(没有工厂)、农耕社会小作坊(简单工厂,民间酒坊)、工业革命流水线(工厂方法,自产自销)、现代产业链代工厂(抽象工厂,富士康)

二、简单工厂模式

1.介绍

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

简单工厂缺点:工厂类的职责相对过重,不易于扩展过于复杂的产品结构

2.案例介绍

案例情景:以课程为例。因为课程有Java,Python,PHP等许多课程

2.1 初始版本

  • 定义一个课程标准ICourse接口
public interface ICourse {
     void record();
}
  • JavaCourse实现类
public class JavaCourse implements ICourse{
    @Override
    public void record() {
        System.out.println("录制Java课程");
    }
}
  • 客户端调用
public class Test {
    public static void main(String[] args) {
        ICourse course = new JavaCourse();
        course.record();
    }
}

看上面的代码,父类ICourse指向子类JavaCourse的引用,应用层代码需要依赖JavaCourse,如果业务扩展,我继续增加PythonCourse 甚至更多,那么我们客户端的依赖会变得越来越臃肿。因此我们要想办法把这种依赖减弱,把创建细节隐藏。虽然目前的代码中,我们创建对象的过程并不复杂,但从代码设计角度来讲不易于扩展。现在,我们用简单工厂模式对代码进行优化。

2.2 简单工厂

  • 先创建一个PythonCourse
public class PythonCourse implements ICourse{
    @Override
    public void record() {
        System.out.println("录制Python课程");
    }
}
  • 再创建CourseFactory工厂类
public class CourseFactory {
    public ICourse create(String className){
        if ("java".equals(name)){
            return new JavaCourse();
        }else if("python".equals(name)){
            return new PythonCourse();
        }else {
            return null;
        }
    }
}
  • 再修改客户端调用代码
public class Test {
    public static void main(String[] args) {
        // 用工厂创建 以后别的课程就不需要大改,只需要传进不同的参数
        ICourse course = new CourseFactory().create("Java");
        course.record();
    }
}

当然,我们为了调用方便,也可将factory的create()改为静态方法

2.3 继续优化

客户端调用是简单了,但如果我们业务继续扩展,要增加前端课程,那么工厂中的create(就要根据产品链的丰富每次都要修改代码逻辑。不符合开闭原则。因此,我们对简单工厂还可以继续优化,可以采用反射技术:

  • 修改CourseFactory的代码
public class CourseFactory {
    public ICourse create(String className){
        // 类加载的方式
        try{
            if (!(null == className || "".equals(className))){
                return (ICourse)Class.forName(className).newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
  • 修改客户端调用代码
public class Test {
    public static void main(String[] args) {
        // 用工厂创建 以后别的课程就不需要大改,只需要传进不同的参数
        ICourse course = new CourseFactory().create("com.DesignLearn.factory.JavaCourse");
        course.record();
    }
}

2.4 继续优化

优化之后,产品不断丰富不需要修改 CourseFactory 中的代码。但是,有个问题是,方法参数是字符串,可控性有待提升,而目还需要强制转型。我们再修改一下代码:

  • CourseFactory
public class CourseFactory {
    public ICourse create(Class<? extends ICourse> clazz){
    if (null != clazz){
            try {
                return clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

  • 修改客户端调用代码
public class Test {
    public static void main(String[] args) {
        // 用工厂创建 以后别的课程就不需要大改,只需要传进不同的参数
        ICourse course = new CourseFactory().create(JavaCourse.class);
        course.record();
    }
}

三、工厂方法模式

1.介绍

工厂方法模式(Fatory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。

2.优点

在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。

3.适用的场景

  • 创建对象需要大量重复的代码。
  • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
  • 一个类通过其子类来指定创建哪个对象。

4.缺点

  • 类的个数容易过多,增加复杂度
  • 增加了系统的抽象性和理解难度

5. 案例

简述:工厂方法模式主要解决产品扩展的问题,在简单工厂中,随着产品链的丰富,如果每个课程的创建逻辑有区别的话,工厂的职责会变得越来越多,有点像万能工厂,并不便于维护。根据单一职责原则我们将职能继续拆分,专人干专事。

Java 课程由Java 工厂创建,Python 课程由 Python 工厂创建,对工厂本身也做一个抽象。

  • 先创建ICourseFactory 接口
public interface ICourseFactory {
    ICourse create();
}
  • 创建子工厂JavaCourseFactory
public class JavaCourseFactory implements ICourseFactory{
    @Override
    public ICourse create() {
        return new JavaCourse();
    }
}
  • 创建子工厂PythonCourseFactory
public class PythonCourseFactory implements ICourseFactory{
    @Override
    public ICourse create() {
        return new PythonCourse();
    }
}

  • ICourse
public interface ICourse {
     void record();
}
  • JavaCourse
public class JavaCourse implements ICourse {
    @Override
    public void record() {
        System.out.println("录制Java课程");
    }
}
  • PythonCourse
public class PythonCourse implements ICourse {
    @Override
    public void record() {
        System.out.println("录制Python课程");
    }
}
  • 测试
public class Test {
    public static void main(String[] args) {
        ICourseFactory factory = new JavaCourseFactory();
        ICourse course = factory.create();
        course.record();
    }
}

  • 类图
    在这里插入图片描述

四、抽象工厂模式

1.定义

抽象工厂模式(Abastract FactoryPattern)是指提供一个创建一系列相关或相互依赖对象的接口无须指定他们具体的类。

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

2.产品等级和产品族

在这里插入图片描述
从上图中看出有正方形,圆形和菱形三种图形,相同颜色深浅的就代表同一个产品族,相同形状的代表同一个产品等级结构。同样可以从生活中来举例,比如,美的电器生产多种家用电器。那么上图中,颜色最深的正方形就代表美的洗衣机、颜色最深的圆形代表美的空调、颜色最深的菱形代表美的热水器颜色最深的一排都属于美的品牌,都是美的电器这个产品族。再看最右侧的菱形,颜色最深的我们指定了代表美的热水器,那么第二排颜色稍微浅一点的菱形,代表海信的热水器。同理,同一产品结构下还有格力热水器,格力空调,格力洗衣机。

从图中可以看到,最左侧的小房子我们就认为具体的工厂有美的工厂,有海信工厂,有格力工厂。 每个品牌的工厂都生产洗衣机、热水器和空调。

3.案例

一个具体的业务场景而且用代码来实现。还是以课程为例,每个课程不仅要提供课程的录播视频,而且还要提供老师的课堂笔记。相当于现在的业务变更为同一个课程不单纯是一个课程信息,要同时包含录播视频、课堂笔记甚至还要提供源码才能构成一个完整的课程。在产品等级中增加两个产品IVideo录播视频和INote 课堂笔记

  • IVideo接口
public interface IVideo {
    void record();
}
  • INote接口
public interface INote {
    void edit();
}
  • 然后创建一个抽象工厂CourseFactory类
/**
 * 产品族工厂,如果没有逻辑的话可以用接口
 * 有逻辑的话可以用抽象类
 */
public abstract class CourseFactory {

    public void init(){
        System.out.println("初始化基础数据");
    }

    protected abstract INote createNote();

    protected abstract IVideo createVideo();
}
  • 创建Java产品族,Java视频JavaVideo类
public class JavaVideo implements IVideo{
    @Override
    public void record() {

    }
}

  • 拓展产品等级Java课堂笔记JavaNote类
public class JavaNote implements INote{
    @Override
    public void edit() {

    }
}
  • 创建Java产品族的具体工厂JavaCourseFactory
public class JavaCourseFactory extends CourseFactory{
    @Override
    protected INote createNote() {
        return new JavaNote();
    }

    @Override
    protected IVideo createVideo() {
        return new JavaVideo();
    }
}
  • 创建Python产品族,Python视频PythonVideo类
public class PythonVideo implements IVideo{
    @Override
    public void record() {

    }
}
  • 拓展产品等级Python课堂笔记JavaNote类
public class PythonNote implements INote{
    @Override
    public void edit() {

    }
}
  • 创建Python产品族的具体工厂PythonCourseFactory
public class PythonCourseFactory extends CourseFactory{
    @Override
    protected INote createNote() {
        return new PythonNote();
    }

    @Override
    protected IVideo createVideo() {
        return new PythonVideo();
    }
}
  • 客户端调用
public class Test {
    public static void main(String[] args) {
        CourseFactory factory = new JavaCourseFactory();
        factory.createNote().edit();
        factory.createVideo().record();
    }
}
  • 类图
    在这里插入图片描述

4.总结

上面的代码完整地描述了两个产品族Java课程和Python课程,也描述了两个产品等级视频和手记。抽
象工厂非常完美清晰地描述这样一层复杂的关系。

但是,不知道大家有没有发现,如果我们再继续扩展
产品等级,将源码Source也加入到课程中,那么我们的代码从抽象工厂,到具体工厂要全部调整,很显然不符合开闭原则。

4.1 抽象工厂的缺点

因此抽象工厂也是有 缺点 的:
1.规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
2.增加了系统的抽象性和理解难度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值