当前位置 博文首页 > 韩超的博客 (hanchao5272):设计模式-工厂模式-3种-以手机制造工

    韩超的博客 (hanchao5272):设计模式-工厂模式-3种-以手机制造工

    作者:[db:作者] 时间:2021-09-05 16:14

    超级链接: Java常用设计模式的实例学习系列-绪论

    参考:《HeadFirst设计模式》


    1.工厂模式存在的意义

    工厂存在的意义是:高效的制造某一类产品。

    工厂模式存在的意义是:高效的创建某一类对象。

    工厂模式有很多种,本文只介绍以下三种:

    • 简单工厂模式,又称静态工厂模式
    • 工厂方法模式,全称多个工厂方法模式
    • 抽象工厂模式

    本文以`手机制造工厂生产手机为场景来学习工厂模式。

    • 手机有两种:苹果手机和安卓手机。
    • 手机制造工厂分别可以制造上述两种手机。

    2.关于手机

    关于手机的编码不过多的叙述,就是很简单的一个父抽象类加两个子实现类的关系。

    父抽象手机类:Phone

    /**
     * <p>手机</P>
     *
     * @author hanchao
     */
    @Getter
    @Setter
    @AllArgsConstructor
    public abstract class Phone {
        private String name;
    
        /**
         * 打个电话测试一下
         */
        public abstract void callTest();
    }
    

    子实现类:苹果手机:ApplePhone

    /**
     * <p>苹果手机</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class ApplePhone extends Phone {
    
        public ApplePhone() {
            super("苹果手机");
        }
    
        @Override
        public void callTest() {
            log.info("使用[" + super.getName() + "]给13322224444打电话.");
        }
    }
    

    子实现类:安卓手机:AndroidPhone

    /**
     * <p>安卓手机</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class AndroidPhone extends Phone {
    
        public AndroidPhone() {
            super("安卓手机");
        }
    
        @Override
        public void callTest() {
            log.info("使用[" + super.getName() + "]给15533335555打电话.");
        }
    }
    

    3.简单/静态工厂模式

    简单工厂模式:一般情况下,创建对象的方法需要传入代表类型的参数type,然后再通过if-else或者switch语句根据type创建对应的对象。

    直接上代码:PhoneFactory

    /**
     * <p>简单工厂:手机工厂</P>
     *
     * @author hanchao
     */
    public class PhoneFactory {
        public static final int TYPE_APPLE = 1;
        public static final int TYPE_ANDROID = 2;
    
        /**
         * 简单工厂:一般情况下,创建对象的方法需要传入代表类型的参数type,然后再通过if-else或者switch语句根据type创建对应的对象。
         */
        public static Phone producePhone(int type) {
            Phone phone;
            switch (type) {
                case TYPE_APPLE:
                    //制造一个苹果手机
                    phone = new ApplePhone();
                    break;
                case TYPE_ANDROID:
                    //制造一个安卓手机
                    phone = new AndroidPhone();
                    break;
                default:
                    throw new IllegalArgumentException("此型号手机暂不制造!");
            }
            return phone;
        }
    }
    
    • 简单工厂的机制很简单:根据传入的类型,创建对应的对象。

    • 这里将可用的类型编写成了静态变量,这用能在一定程度上减少出错的可能。

    然后,写一个简单的测试类:SimpleFactoryDemo

    /**
     * <p>1.简单工厂模式</P>
     *
     * @author hanchao
     */
    public class SimpleFactoryDemo {
    
        public static void main(String[] args) {
            //某客户下了一笔大单子,要求制造2台苹果手机和1台安卓手机
            //于是手机工厂开始了制造
    
            //先来一台苹果手机
            Phone phone = PhoneFactory.producePhone(PhoneFactory.TYPE_APPLE);
            //测试一下
            phone.callTest();
    
            //再来一台苹果手机
            phone = PhoneFactory.producePhone(PhoneFactory.TYPE_APPLE);
            //测试一下
            phone.callTest();
    
            //再来一台安卓手机
            phone = PhoneFactory.producePhone(PhoneFactory.TYPE_ANDROID);
            //测试一下
            phone.callTest();
        }
    }
    

    运行结果:

    2019-06-30 15:03:10,353  INFO [main-1] pers.hanchao.designpattern.factory.simple.telephone.ApplePhone:19 - 使用[苹果手机]给13322224444打电话. 
    2019-06-30 15:03:10,357  INFO [main-1] pers.hanchao.designpattern.factory.simple.telephone.ApplePhone:19 - 使用[苹果手机]给13322224444打电话. 
    2019-06-30 15:03:10,358  INFO [main-1] pers.hanchao.designpattern.factory.simple.telephone.AndroidPhone:19 - 使用[安卓手机]给15533335555打电话. 
    

    3.1.简单/静态工厂模式的总结

    **简单工厂:**一般情况下,创建对象的方法需要传入代表类型的参数type,然后再通过if-else或者switch语句根据type创建对应的对象。

    通常提供的创建对象的方法是静态的,所以简单工厂模式也称之为静态工厂模式

    3.2.简单/静态工厂模式的优点

    • 实现简单:代码逻辑很简单。
    • 可复用高:所有对象的创建都通过同名的方法创建。

    3.3.简单/静态工厂模式的缺点

    • 容错率低,如果传入的类型参数type因为粗心写错,则创建的产品会与预期不符。
    • 耦合度高,每增减一种产品,都需要对创建对象的唯一方法进行修改。
    • 扩展性差,每增减一种产品,都需要修改工厂类,违背了设计模式的开放-封闭原则(OCP,对扩展开放,对修改关闭)。

    造成以上缺点的关键在于:所有对象的创建都通过唯一的工厂方法。

    为了解决以上问题,尝试为每种对象提供相应的工厂方法。如此进化成了:多个工厂方法模式。

    4.(多个)工厂方法模式

    (多个)工厂方法模式的关键点在于:为每种对象提供相应的工厂方法,所以很容易得到如下的工厂类:

    PhoneFactory

    /**
     * <p>多个工厂方法模式:手机工厂</P>
     *
     * @author hanchao
     */
    public class PhoneFactory {
    
        /**
         * 制造一个苹果手机
         */
        public static Phone produceApplePhone() {
            return new ApplePhone();
        }
    
        /**
         * 制造一个安卓手机
         */
        public static Phone produceAndroidPhone() {
            return new AndroidPhone();
        }
    }
    

    然后,写一个简单的测试类:MultiFactoryMethodsDemo

    /**
     * <p>2.多个工厂方法模式</P>
     *
     * @author hanchao
     */
    public class MultiFactoryMethodsDemo {
    
        public static void main(String[] args) {
            //某客户下了一笔大单子,要求制造2台苹果手机和1台安卓手机
            //于是手机工厂开始了制造
    
            //先来一台苹果手机
            Phone phone = PhoneFactory.produceApplePhone();
            //测试一下
            phone.callTest();
    
            //再来一台苹果手机
            phone = PhoneFactory.produceApplePhone();
            //测试一下
            phone.callTest();
    
            //再来一台安卓手机
            phone = PhoneFactory.produceAndroidPhone();
            //测试一下
            phone.callTest();
        }
    }
    

    运行结果:略

    4.1.(多个)工厂方法模式的总结

    多个工厂方法模式: 每种对象分别编写专用的创建方法,根据调用的创建方法的不同,产生不同的对象。

    多个工厂方法模式又简称为工厂方法模式

    4.2.(多个)工厂方法模式的优点

    • 实现简单:代码逻辑很简单。
    • 容错率高,因为每种对象都有专用的创建方法,无需传入类型等参数,只要调用正确的创建方法就不会出错。
    • 耦合度低,每增减一种产品,只需要增减一个创建方法,不会影响其他对象的创建方法。

    4.3.(多个)工厂方法模式的缺点

    • 扩展性差,每增减一种产品,都需要修改工厂类,违背了设计模式的开放-封闭原则(OCP,对扩展开放,对修改关闭)。
    • 可复用低,所有对象的创建方法都不同名。

    造成以上缺点的关键在于:所有对象的创建方法都存在于唯一个工厂。

    为了解决以上问题,尝试为每种对象提供单独的工厂及工厂方法。如此进化成了:抽象工厂模式。

    5.抽象工厂模式

    抽象工厂模式的关键点在于:``为每种对象提供单独的工厂及工厂方法`。

    所以需要把工厂类抽象出来,形成抽象工厂,然后针对每种对象分别实现专用的工厂及工厂方法,这就是命名抽象工厂的由来。

    抽象工厂:AbstractPhoneFactory

    /**
     * <p>抽象手机工厂</P>
     *
     * @author hanhao
     */
    public abstract class AbstractPhoneFactory {
        /**
         * 制造手机
         *
         * @return 手机
         */
        public abstract Phone producePhone();
    }
    

    苹果手机专用的工厂及创建方法:ApplePhoneFactory

    /**
     * <p>具体工厂:苹果手机工厂</P>
     *
     * @author hanchao
     */
    public class ApplePhoneFactory extends AbstractPhoneFactory {
    
        @Override
        public Phone producePhone() {
            return new ApplePhone();
        }
    }
    

    安卓手机专用的工厂及创建方法:AndroidPhoneFactory

    /**
     * <p>具体工厂:安卓手机工厂</P>
     *
     * @author hanchao
     */
    public class AndroidPhoneFactory extends AbstractPhoneFactory {
    
        @Override
        public Phone producePhone() {
            return new AndroidPhone();
        }
    }
    

    然后,写一个简单的测试类:AbstractFactoryDemo

    /**
     * <p>3.抽象工厂模式</P>
     *
     * @author hanchao
     */
    public class AbstractFactoryDemo {
    
        public static void main(String[] args) {
            //某客户下了一笔大单子,要求制造2台苹果手机和1台安卓手机
            //于是手机工厂开始了制造
    
            //先来一台苹果手机
            Phone phone = new ApplePhoneFactory().producePhone();
            //测试一下
            phone.callTest();
    
            //再来一台苹果手机
            phone = new ApplePhoneFactory().producePhone();
            //测试一下
            phone.callTest();
    
            //再来一台安卓手机
            phone = new AndroidPhoneFactory().producePhone();
            //测试一下
            phone.callTest();
        }
    }
    

    运行结果:略

    5.1.抽象工厂模式的总结

    抽象工厂模式: 定义一个抽象工厂和抽象方法,每种对象都有专用的子工厂及对象创建方法。

    5.2.抽象工厂模式的优点

    • 容错率高,因为每种对象都有专用的工厂及创建方法,只要调用正确的工厂的创建方法就不会出错。
    • 耦合度低,每增减一种产品,只需增减一个工厂及创建方法,不会影响其他对象的创建方法。
    • 扩展性好,每增减一种产品,只需增减此对象的工厂及创建方法,不修改其他工厂,遵循了开放-封闭原则(OCP,对扩展开放,对修改关闭)。
    • 可复用高,所有对象的创建都通过同名的方法创建。

    5.3.抽象工厂模式的缺点

    • 实现复杂:代码逻辑相对复杂。可能100种对象,需要定义100个工厂类。

    6.总结

    最后以UML类图来总结本文的三种工厂模式。

    在这里插入图片描述

    从设计模式原则考虑,上述三种工厂模式的推荐优先级:抽象工厂模式 >>>(多个)工厂方法模式>>>简单/静态工厂模式

    不过凡事不绝对,如果你说你能百分百的保证业务场景不会发生变动,那你是用哪种模式都是无所谓的。

    cs