261-模式的秘密---工厂模式

系列课程:模式宗师养成宝典之Java版

http://www.imooc.com/learn/261

简介:工厂模式和抽象工厂模式是在日常开发中使用非常广泛的设计模式。主要用于实现将对象的实例化部分取出来,进而优化系统架构,增强系统的扩展性。本课程即将讲解Java中的工厂模式和抽象工厂模式的应用。

第1章 工厂模式概述

本章主要介绍工厂模式的基本概念。

1-1 工厂模式概述 (10:29)

什么是设计模式?

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结

应用设计模式的好处?

设计模式是优秀的使用案例
使用设计模式可提高代码的重用性
让代码更容易被他人理解
保证代码可靠性

重点内容

  • 工厂模式的概念
  • 工厂模式的意图
  • 工厂模式的应用场景
  • 工厂模式的设计思想
  • 工厂模式的好处

工厂模式的概念

实例化对象,用工厂方法代替new操作
工厂模式包括工厂方法模式和抽象工厂模式
抽象工厂模式是工厂方法模式的扩展

工厂模式的意图

定义一个接口来创建对象,但是让子类来决定哪些类需要被实例化
工厂方法把实例化的工作推迟到子类中去实现

什么情况下适合工厂模式

有一组类似的对象需要创建
在编码时不能预见需要创建哪种类的实例
系统需要考虑扩展性,不应依赖于产品类实例如何被创建、组合和表达的细节

项目中的现状

在软件系统中经常面临着“对象”的创建工作,由于需求的变化,这个对象可能随之也会发生变化,但它却拥有比较稳定的接口。为此,我们需要提供一种封装机制来隔离出这个易变对象的变化,从而保证系统中其他依赖该对象的对象不随着需求变化而变化。

基于项目现状将代码进行如下设计

  1. 尽量松耦合,一个对象的依赖对象的变化与本身无关
  2. 具体产品与客户端剥离,责任分割

工厂方法模式类图

工厂方法模式类图

抽象工厂模式类图

抽象工厂模式类图 工厂产品族

第2章 工厂模式应用

本章通过案例演示工厂模式的应用。

2-1 工厂模式应用 (22:18)

  1. 发型接口HairInterface.java

    public interface HairInterface {
        // 画发型
        void draw();
    }
  2. 左偏分发型LeftHair.java

    public class LeftHair implements HairInterface {
        @Override
        public void draw() {
            System.out.println("左偏分发型");
        }
    }
  3. 右偏分发型RightHair.java

    public class RightHair implements HairInterface {
        @Override
        public void draw() {
            System.out.println("右偏分发型");
        }
    }
  4. 中分发型InHair.java

    public class InHair implements HairInterface {
        @Override
        public void draw() {
            System.out.println("中分发型");
        }
    }
  5. 配置文件application.properties

    left=com.tuyrk.hair.impl.LeftHair
    right=com.tuyrk.hair.impl.RightHair
    in=com.tuyrk.hair.impl.InHair
  6. properties文件的读取工具类PropertiesReader.java

    public class PropertiesReader {
        // 获取配置文件的属性
        public static Map<String, String> getProperties() {
            Map<String, String> map = new HashMap<>();
            try {
                Resource resource = new ClassPathResource("application.properties");
                Properties props = PropertiesLoaderUtils.loadProperties(resource);
                Enumeration<?> en = props.propertyNames();
                while (en.hasMoreElements()) {
                    String key = (String) en.nextElement();
                    String property = props.getProperty(key);
                    map.put(key, property);
                }
            } catch (IOException e) {}
            return map;
        }
    }
  7. 发型工厂HairFactory.java

    public class HairFactory {
        /**
         * 根据类型来创建对象
         * @param key 发型种类
         * @return 发型实例
         */
        public HairInterface getHair(String key) {
            if ("left".equals(key)) {
                return new LeftHair();
            } else if ("right".equals(key)) {
                return new RightHair();
            }
            return null;
        }
    
        /**
         * 根据类的名称来生产对象
         * @param className 类名
         * @return 发型实例
         */
        public HairInterface getHairByClass(String className) {
            try {
                return (HairInterface) Class.forName(className).newInstance();
            } catch (Exception e) {}
            return null;
        }
    
        /**
         * 根据类的名称来生产对象
         * @param key 类名对应名称
         * @return 发型实例
         */
        public HairInterface getHairByClassKey(String key) {
            try {
                Map<String, String> map = PropertiesReader.getProperties();
                return (HairInterface) Class.forName(map.get(key)).newInstance();
            } catch (Exception e) {}
            return null;
        }
    }
    
  8. 测试类Test.java

    public class Test {
        public static void main(String[] args) {
            // 每需要创建一个发型都需要重新new,并且调用draw()
            /*HairInterface left = new LeftHair();
            left.draw();
            HairInterface right = new RightHair();
            right.draw();*/
    
            // if-else实现
            /*HairFactory factory = new HairFactory();
            HairInterface left = factory.getHair("left");
            left.draw();*/
    
            // className实现
            /*HairFactory factory = new HairFactory();
             *//*HairInterface left = factory.getHairByClass("com.tuyrk.hair.impl.LeftHair");*//*
            HairInterface left = factory.getHairByClass(LeftHair.class.getName());
            left.draw();*/
    
            // 读取properties实现
            HairFactory factory = new HairFactory();
            HairInterface hair = factory.getHairByClassKey("in");
            hair.draw();
        }
    }

第3章 抽象工厂模式应用

本章通过案例演示抽象工厂模式的应用

3-1 抽象工厂模式应用 (12:34)

  1. 男孩Boy.java

    public interface Boy {
        void drawMan();
    }
  2. 女孩Girl.java

    public interface Girl {
        void drawWomen();
    }
  3. 新年系列的男孩HNBoy.java

    public class HNBoy implements Boy {
        @Override
        public void drawMan() {
            System.out.println("新年男孩");
        }
    }
  4. 新年系列的女孩HNGirl.java

    public class HNGirl implements Girl {
        @Override
        public void drawWomen() {
            System.out.println("新年女孩");
        }
    }
  5. 圣诞系列的男孩MCBoy.java

    public class MCBoy implements Boy {
        @Override
        public void drawMan() {
            System.out.println("圣诞男孩");
        }
    }
  6. 圣诞系列的女孩MCGirl.java

    public class MCGirl implements Girl {
        @Override
        public void drawWomen() {
            System.out.println("圣诞女孩");
        }
    }
  7. 人物的实现接口PersonFactory.java

    public interface PersonFactory {
        // 男孩接口
        Boy getBoy();
        // 女孩接口
        Girl getGirl();
    }
  8. 新年系列工厂HNFactory.java

    public class HNFactory implements PersonFactory {
        @Override
        public Boy getBoy() {
            return new HNBoy();
        }
    
        @Override
        public Girl getGirl() {
            return new HNGirl();
        }
    }
  9. 圣诞系列工厂MCFactory.java

    public class MCFactory implements PersonFactory {
        @Override
        public Boy getBoy() {
            return new MCBoy();
        }
    
        @Override
        public Girl getGirl() {
            return new MCGirl();
        }
    }
  10. 测试类Test.java

    public class Test {
        public static void main(String[] args) {
            // 圣诞女孩
            PersonFactory mcFactory = new MCFactory();
            Girl girl = mcFactory.getGirl();
            girl.drawWomen();// 圣诞女孩
    
            // 新年男孩
            PersonFactory hnFactory = new HNFactory();
            Boy boy = hnFactory.getBoy();
            boy.drawMan();// 新年男孩
        }
    }

第4章 总结

总结工厂模式和抽象工厂模式的应用。

4-1 总结 (06:06)

场景应用

  • JDBC

    是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成

    JDBC
  • Spring BeanFactory

    BeanFactory,作为Spring基础的IoC容器,是Spring的一个Bean工厂。如果单从工厂模式的角度思考,他就是用来“生产Bean”,然后提供给客户端。

    Bean的实例化过程如下:

    1. 调用Bean的默认构造方法,或指定的构造方法,生成bean实例(暂称为instance1)
    2. 如果Bean的配置文件中注入了Bean属性值,则在instance1基础上进行属性注入形成instance2,这种注入是覆盖性的。
    3. 如果Bean实现了InitializingBean接口,则调用afterPropertiesSet()方法,来改变或操作instance2,得到instance3
    4. 如果Bean的配置文件中指定了init-method=”init”属性,则会调用指定的初始化方法,则在instance3的基础上调用初始化方法init(),将对象最终初始化为instance4;当然,这个初始化的名字是任意的。

工厂方法模式和抽象工厂模式对比

工厂模式是一种极端情况下的抽象工厂模式,而抽象工厂模式可以看成是工厂模式的推广。
工厂模式用来创建一个产品的等级结构,而抽象工厂模式是用来创建多个产品的等级结构
工厂模式只有一个抽象产品类,而抽象工厂模式有多个抽象产品类

工厂模式的实现帮助我们

系统可以在不修改具体工厂角色的情况下引进新的产品
客户端不必关心对象如何创建,明确了职责
更好的理解面向对象的原则。面向接口编程,而不要面向实现编程

工厂模式适用于哪些场景

一个系统应当不依赖于产品类实例被创立,组成和表示的细节。这对所有形态的工厂模式都是重要的
这个系统的产品有至少一个的产品族
同属于一个产品族的产品是设计成在一起使用的。这个约束必须得在系统的设计中体现出来
不同的产品以一系列的接口的面貌出现,从而使系统不依赖于接口实现的细节


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 tuyrk@qq.com

文章标题:261-模式的秘密---工厂模式

文章字数:2.1k

本文作者:神秘的小岛岛

发布时间:2019-12-15, 11:57:46

最后更新:2020-01-05, 14:33:25

原始链接:https://www.tuyrk.cn/imooc/261-factory-mode/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏