• Java设计模式(四)工厂方法模式


    定义与类型

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

    适用场景

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

    优点

    • 用户只需要关心所需产品对应的工厂,无须关心创建细节
    • 加入新产品符合开闭原则,提高可扩展性

    缺点

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

    Coding

    工厂方法模式从一定意义上讲是从简单工厂模式衍生过来的,创建产品抽象类

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

    创建具体产品

    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视频");
        }
    }
    

    创建产品工厂方法抽象类

    public abstract class VideoFactory {
        public abstract Video getVideo();
    }
    

    创建产品工厂方法实现类(每个产品都有对应的实现类)

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

    测试类

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

    控制台输出

    录制Java课程
    录制Python视频
    

    如果我们现在新增一个产品--前端课程,我们需要创建产品类,产品工厂类,但是无需改动其他代码,做到了对扩展开放,对修改关闭,符合开闭原则。

    public class FEVideo extends Video {
        @Override
        public void produce() {
            System.out.println("录制前端课程");
        }
    }
    public class FEVideoFactory extends VideoFactory {
        @Override
        public Video getVideo() {
            return new FEVideo();
        }
    }
    

    但是,我们也不难看出工厂方法模式的缺点--类的个数容易过多,增加复杂度。

    因为一旦我们需要现在产品,就需要创建产品对应的产品实现类,以及产品工厂方法类,无疑增加了类的个数和系统的复杂度。

    完整的UML类图

    源码解析

    Collection源码

    jdk中典型的工厂方法模式体现为java.util.Collection

    抽象产品为java.util.Iterator

    public interface Iterator<E> {
    	...
    }
    

    抽象工厂定义了创建产品族的方法java.util.Collection.#iterator

    Iterator<E> iterator();
    

    由子类来定义具体创建产品的逻辑,如java.util.ArrayList.#iterator

    public Iterator<E> iterator() {
        return new Itr();
    }
    

    而具体的产品定义为java.util.ArrayList$Itr

    private class Itr implements Iterator<E> {
        ...
    }
    

    UML类图

    URLStreamHandlerFactory源码

    再来看一个典型例子,java.net.URLStreamHandlerFactory作为工厂方法抽象类,定义了创建产品的抽象方法

    public interface URLStreamHandlerFactory {
        URLStreamHandler createURLStreamHandler(String protocol);
    }
    

    产品抽象类就是java.net.URLStreamHandler

    public abstract class URLStreamHandler {
        ...
    }
    

    产品的工厂方法实现类为sun.misc.Launcher$Factory

    private static class Factory implements URLStreamHandlerFactory {
        ...
        public URLStreamHandler createURLStreamHandler(String var1) {
            private static String PREFIX = "sun.net.www.protocol";
    
            private Factory() {
            }
    
            public URLStreamHandler createURLStreamHandler(String var1) {
                String var2 = PREFIX + "." + var1 + ".Handler";
    
                try {
                    // 通过反射创建指定类型的产品
                    Class var3 = Class.forName(var2);
                    return (URLStreamHandler)var3.newInstance();
                } catch (ReflectiveOperationException var4) {
                    throw new InternalError("could not load " + var1 + "system protocol handler", var4);
                }
            }
        }
    }
    

    可以发现,工厂实现类通过反射类创建具体的产品实现类,而产品实现类非常多

    这样满足了开闭原则,也没有过多的增加类的数量,值得我们学习。

  • 相关阅读:
    犀牛书学习笔记(2):对象和数组
    犀牛书学习笔记(1):语法结构、数据类型和值、表达式和运算符
    小学了一下css hack
    git学习系列--六分之一
    稍览了一下CommonJS
    意识流_六分之一
    两升的心思系列之-----粒子的预备
    mybatis_延迟加载
    mybatis_动态SQL
    mybatis_mapper动态代理
  • 原文地址:https://www.cnblogs.com/gcdd/p/12292128.html
Copyright © 2020-2023  润新知