【Java设计模式】搭配案例+源码,理解简单工厂和工厂方法

我是清风~,每天学习一点点,快乐成长多一点,这些都是我的日常笔记以及总结。

简单工厂

  • 定义:由一个工厂对象决定创建出哪一种产品类的实例
  • 类型:创建型,但不属于GOF23种设计模式
    抽象工厂和工厂方法都是由简单工厂一步一步引进。

适用场景

  1. 工厂类负责创建的对象比较少
  2. 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心

优点

  1. 只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道创建细节
    工厂类含义必要的判断逻辑,可以决定在什么时候创建那个产品的实例,客户端可以免除直接创建产品对象的责任。如果我要创建一杯咖啡,简单工厂就直接返回一杯咖啡就行了

缺点

  1. 工厂类的职责相对过着,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则。
    因为工厂类集中了产品创建逻辑,一旦出现问题,出现bug,整个系统都会受到影响。
    在使用简单工厂的时候,也会增加系统种类的个数,从类的角度来说,增加了系统的复杂度,和理解难度。
    一旦增加新的产品,不得不修改产品逻辑。在产品逻辑非常多的时候, 这个工厂逻辑就会过于复杂,不利于维护和扩展。
  2. 简单工厂无法形成基于继承的等级结构。

业务场景

例如,CSDN上面有java的视频,python视频
创建生产视频的抽象方法,假如java和python的视频生产的时候不一样

public abstract class Video {
    public abstract void produce();
}

紧接java视频的实现类

public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("学习Java课程视频");
    }
}
public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("学习Python课程视频");
    }
}

使用test客户端应用层类,非常需要依赖对应的类
使用简单工厂,在这里将创建具体的过程视频移植到简单工厂里面

public class VideoFactory {
    public Video getVideo(String type){
        if("java".equalsIgnoreCase(type)){
            return new JavaVideo();
        }else if("python".equalsIgnoreCase(type)){
            return new PythonVideo();
        }
        return null;
    }

}

测试

public class Test {
    public static void main(String[] args) {
     VideoFactory videoFactory = new VideoFactory();
        Video video = videoFactory.getVideo("java");
        if(video == null){
            return;
        }
        video.produce();
    }
}
输出结果
录制Java课程视频

原来test客户端直接依赖对应的javaVideo和PythonVideo,现在并不是了。
这个应用层test依赖VideoFactory,VideoFactory它来创建java视频还是python视频,具体的生产过程都在VideoFactory,test只管直接使用
在这里插入图片描述

源码分析–Calendar类

JDK源码:简单工厂的体现
ctrl+N 搜索 Calendar这个类

public static Calendar getInstance()
    {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }

进到createCalendar
里面有个 if 判断跟上面的VideoFactory差不多,语言,国家,然后就会返回这个实现,否则就会返回另外一个实现,下面的又返回了一个日本的实现

 if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                case "buddhist":
                cal = new BuddhistCalendar(zone, aLocale);
                    break;
                case "japanese":
                    cal = new JapaneseImperialCalendar(zone, aLocale);
                    break;
                case "gregory":
                    cal = new GregorianCalendar(zone, aLocale);
                    break;
                }
            }
        }

Calendar 实现了三个接口(序列号接口、比较、克隆),下面就是继承,Calendar 类的子类。
Calendar 是一个抽象类
在这里插入图片描述

工厂方法

  • 定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类
    工厂方法让类的实例化推迟到子类中进行
  • 类型:创建型

使用场景:

  1. 创建对象需要大量重复的代码,这个时候就可以考虑工厂方法适不适用在这里。
  2. 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
  3. 一个类通过其子类来只定创建哪个对象。
    在这个模式中,客户端也不需要知道具体产品类的类名只需要知道所定义的工厂就可以了,具体的产品对象都由工厂来创建,客户端只需要知道我要的产品是在哪个工厂里。
    在这个模式中,利用面向对象的多态性和里氏替换原则子类对象将覆盖父类对象,从而使系统更容易扩展。
    同时,注意,把创建对象的过程推迟到子类来实现,所以创建对象的任务就委托给多个工厂的子类中的某一个,客户端在使用时无需关心是哪一个工厂子类创建产品子类,需要的时候动态指定即可

优点

  1. 用户只需要关心所需产品对应的工厂,无须关心创建细节
  2. 加入新产品符合开闭原则,提高可可扩展性
    在工厂模式中,用它来创建所需要的产品,同时又隐藏了具体产品类被实例化的细节。我们只需要关心产品对应的工厂,无需关系创建细节。

缺点

  1. 类的个数容易过多,增加复杂度
  2. 增加了系统的抽象性和理解难度
    类的个数怎么看,在添加新的产品的时候,要编写新的产品类,而且还要提高这个产品类与之对应的具体工厂类,所以类的个数会增加,系统复杂度也增加

业务场景

与简单工厂一样,CSDN上面有java的视频,python视频,大数据课程

public abstract class Video {
    public abstract void produce();
}

紧接java视频的实现类

public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("学习Java课程视频");
    }
}

紧接 Python视频的实现类

public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("学习Python课程视频");
    }
}

紧接 Data视频的实现类

public class DataVideo extends Video {
    @Override
    public void produce() {
        System.out.println("学习Data课程视频");
    }
}

这里的VideoFactory改成抽象方法

在子类中不需要传了,具体调用哪个实现,全部交由子类来实现
通过定义VideoFactory这个抽象类里面的getVideo方法,就是定义了一个规范。
为什么要使用抽象类,因为 这个类有可能对于某些行为,甚至某些属性是已知的,虽然这里有可能有抽象方法,还有已知的实现,用抽象类就比较合适
那如果这里全是未知的,完全可以使用接口来定义

public abstract class VideoFactory {

    public abstract Video getVideo();
}

java视频、python视频都属于一个视频等级
产品等级、产品图是对比工厂方法的 概念
工厂方法是为了解决同一等级的业务抽象问题

先创建一个java视频的工厂

public class JavaVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }
}

创建一个python视频的工厂

public class PythonVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }
}

创建大数据视频工厂

public class DataVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new DataVideo();
    }
}

现在体会一下,具体产生什么样的视频,是由这个VideoFactory的子类来决定的
而不是交由VideoFactory来决定了
VideoFactory只定义规范锲约,并不规范产生哪一种类的视频
产生哪一类的视频完全交由子类来决定。
测试

public class Test {
    public static void main(String[] args) {
        VideoFactory videoFactory = new PythonVideoFactory();
        VideoFactory videoFactory2 = new JavaVideoFactory();
        VideoFactory videoFactory3 = new DataVideoFactory();
        Video video = videoFactory.getVideo();
        video.produce();
    }
}

现在只想学习python

输出结果
录制Python课程视频

UML类图
video下面

  • data视频,python视频,java视频,她们属于同一产品等级
  • data笔记,python笔记,java笔记,她们属于同一产品等级
  • java的笔记,java的视频,都属于java编程,属于同一产品族
  • python的笔记,python的视频,都属于python编程,属于同一产品族
    抽象工厂就是解决产品族的问题

抽象的工厂VideoFactory有三个子类,java视频工厂,data视频工厂,python视频工厂
依赖关系:
java视频工厂创建javavideo,data视频工厂创建datavideo,python视频工厂创建pythonvideo
就是VideoFactory把创建具体某个视频的职责交由子类来实现了,不在负责创建具体的课程视频

要是我想增加前端视频,那么只需要扩展video子类和VideoFactory子类即可
因为是对扩展开发的,不需要修改已有的类,降低了引入风险的可能性

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

源码分析-Collection集合类

JDK源码
在这里插入图片描述
在这接口中定义的iterator,这个方法就是工厂方法
整体Collection可以想象是一个抽象工厂

    /**
    * @return an <tt>Iterator</tt> over the elements in this collection
     */
    Iterator<E> iterator();

这其中方法的实现,就全交由子类Itr来实现了
使用不同的iterator方法得到不同的具体产品实例
我们可以认为ArrayList就是一个具体实现工厂方法
在这里插入图片描述
而具体的抽象产品就是iterator接口
在这里插入图片描述
实际生产出来的产品就是ArrayList里面的Itr这个对象
在这里填写具体的实现,同时在具体的工厂里面返回具体的产品
这个产品是iterator抽象产品的实例
在这里插入图片描述
看下Itr的UML类图
抽象产品具体的arraylist里面的实际产品,这个类是跟arraylist是由依赖关系的
就是arraylist依赖它,Itr作为arraylist方法的iterator方法的一个返回值,
就是说,itr类型虽然是iterator接口类型,但是他是一个具体的产品
在这里插入图片描述
再看下arraylist的UML类图
从这里看出arraylist实现的接口,和其他接口抽象类直接的关系
在这里插入图片描述
我们看arraylist方法的iterator是依赖itr对象的,
所以他们直接是依赖关系
在这里插入图片描述

发布了17 篇原创文章 · 获赞 18 · 访问量 3827

猜你喜欢

转载自blog.csdn.net/weixin_43464303/article/details/105620943
今日推荐