美文网首页
创建型-工厂方法(Factory Method)

创建型-工厂方法(Factory Method)

作者: DoneWillianm | 来源:发表于2020-09-15 10:13 被阅读0次

    工厂方法(Factory Method)

    [TOC]

    工厂模式真心是一个老生常谈的话题了,都已经馊了。。。同时也衍生出很多耳熟能详的XX工厂模式,下面咱们就来学习下这个馊厂模式。

    定义

    惯例搬运:
    Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses
    定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

    白话:
    这里的抽象接口也可以看做是抽象方法或者接口,不用在意文字的字面意思,相当于对外公开一个功能,而这个功能就是new对象,而要实例化出来的对象是什么对象,工厂本身不管,上层自然指挥你该干啥就干啥,只负责索要和持有这个抽象的对象接口

    通用的工厂写法思路:

    1. 定义抽象的产品(对象)接口或是抽象类
    2. 定义抽象工厂,定义产生实例的抽象方法,具体参数自定义,返回抽象产品(对象)
    3. 定义具体的工厂类,继承抽象工厂类,写具体实现代码
    4. 定义具体的产品类,实现相关的方法

    code

    好了,接下来就是结合实例来完成上面的4个步骤,coding~

    背景

    写代码之前,先介绍一下咱们的代码背景。老惯例,XX荣耀,先来一波英雄的基础设定,英雄都什么类型?除了男女外- - 当然是属性啊,主物理还是主AP(尼玛AP怎么说,魔法伤害?)

    public interface IHero {
        /**
         * hero type magic or physical?
         *
         * @return
         */
        String getType();
    
        /**
         * attack by magic or physical
         */
        void attack();
    }
    

    具体含义请参阅老衲蹩脚的注释,谢谢~
    然后是第二步,抽象工厂,很简单,就定义一个产生产品(对象)的抽象方法

    public abstract static class AbsHeroFactory {
    
        public abstract <HERO extends IHero> HERO createHero(Class hero);
        
    }
    

    接下来是定义具体的工厂类,集成上面的抽象工厂,实现抽象方法,说白了就是实例化子类对象

    public static class HeroFactory extends AbsHeroFactory {
    
        @Override
        public <HERO extends IHero> HERO createHero(Class hero) {
            try {
                Constructor declaredConstructor = hero.getDeclaredConstructor();
                declaredConstructor.setAccessible(true);
                IHero iHero = (IHero) declaredConstructor.newInstance();
                return (HERO) iHero;
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassCastException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    最后就是咱们的英雄对象了,先来个鲁班?

    public static class LuBan implements IHero {
    
        @Override
        public String getType() {
            return ATTACK_PHYSICAL;
        }
    
        @Override
        public void attack() {
            System.out.println("yi dun luan pen, zao cheng ATTACK PHYSICAL shang hai:10000");
        }
    
        @Override
        public String toString() {
            return "i am " + ATTACK_PHYSICAL + " AD-Carry";
        }
    }
    
    

    一个ADC不够,再来个AP?

    public static class XiaoQiao implements IHero {
    
    
        @Override
        public String getType() {
            return ATTACK_MAGIC;
        }
    
        @Override
        public void attack() {
            System.out.println("yi dun luan pao, zao cheng ATTACK MAGIC shang hai:10000");
        }
    
        @Override
        public String toString() {
            return "i am " + ATTACK_MAGIC + " AP-Carry";
        }
    }
    
    
    main(){
        HeroFactory heroFactory = new HeroFactory();
        IHero luBan = heroFactory.createHero(LuBan.class);
        IHero xiaoQiao = heroFactory.createHero(XiaoQiao.class);
        System.out.println(luBan.toString());
        luBan.attack();
        System.out.println(xiaoQiao.toString());
        xiaoQiao.attack();
    }
    
    //log
    //i am ATTACK_PHYSICAL AD-Carry
    //yi dun luan pen, zao cheng ATTACK PHYSICAL shang hai:10000
    //i am ATTACK_MAGIC AP-Carry
    //yi dun luan pao, zao cheng ATTACK MAGIC shang hai:10000
    

    OK~上面的写法就是通常工厂的写法,特点在哪里?莫名其妙的4个步骤,
    上层调用者不需要怎么创建对象,通过持有接口对象利用接口对象完成实例化产品(对象)的过程,这样就降低了两个模块之间的耦合,同时来看看扩展性,如果要新增加一个英雄盾山,只需要一个盾山类即可,传入对应类就能拿到对应的盾山英雄对象,工厂无需做任何修改,多爽?不过再写的时候,一定要写好英雄(即产品对象)的抽象接口,最好有一层抽象类来空实现,上层只需要调用英雄接口就能很好的参团了。

    下面搬运:
    <font color="#FF0000">
    工厂方法模式是典型的解耦框架。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要的就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类
    </font>

    使用场景

    先搬运:

    <font color="#FF0000">
    工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。 需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式
    </font>

    感觉不是很好理解,不存在的,白话来一波~

    纯属个人理解,不误人子弟,有错误的地方,欢迎进群指正929891705

    凡是new对象的地方,都可以用工厂来替代,那何时用工厂进行替代呢?这么思考,譬如说进行网络请求,那么我们肯定会有一个对象来负责进行网络请求,而网络请求有着不同的应用协议,而他们的功能几乎一致,那么多种协议必然对应着多种对象,这些对象的实例化过程如果放到上层中,那么业务和功能的耦合就会导致后期的迭代维护痛苦不堪,如果上层仅持有功能接口对象,针对不同的协议通过中间件去实例化具体的对象,那么完全不会对既有的逻辑产生任何影响。而这种做法,就是工厂模式要解决的应用场景了

    简单工厂模式

    简单工厂其实很简单,省掉上述的步骤2:创建抽象工厂。
    直接把实体工厂类重写的抽象方法更换成静态方法,这里就直接贴出静态方法的类以及上层调用了

    private static class HeroFactory {
    
        public static <HERO extends IHero> HERO createHero(Class hero) {
            try {
                Constructor declaredConstructor = hero.getDeclaredConstructor();
                declaredConstructor.setAccessible(true);
                IHero iHero = (IHero) declaredConstructor.newInstance();
                return (HERO) iHero;
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassCastException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    public static void main(String[] args) {
        IHero luBan = HeroFactory.createHero(LuBan.class);
        IHero xiaoQiao = HeroFactory.createHero(XiaoQiao.class);
        System.out.println(luBan.toString());
        luBan.attack();
        System.out.println(xiaoQiao.toString());
        xiaoQiao.attack();
    }
        
        
    //log
    //i am ATTACK_PHYSICAL AD-Carry
    //yi dun luan pen, zao cheng ATTACK PHYSICAL shang hai:10000
    //i am ATTACK_MAGIC AP-Carry
    //yi dun luan pao, zao cheng ATTACK MAGIC shang hai:10000
    

    具体的讲解就直接搬过来了,很通俗易懂,不过一定要仔细理解哈~

    该模式是工厂方法模式的弱化,因为简单,所以称为简单工厂模式(Simple Factory Pattern),也叫做静态工厂模式。在实际项目中,采用该方法的案例还是比较多的,其缺点是工厂类的扩展比较困难,不符合开闭原则,但它仍然是一个非常实用的设计模式。

    多重工厂

    这个命名也是看书得来的,挺想象,直接结合上面的理解就能知道,这种方式的写法其实就是多种工厂,为何要衍生出这种写法呢?

    当我们要生产的英雄有各种各样的骚操作怎么办?譬如说有4个技能,带真实伤害的那种如何是好?术语来说就是产片类种类繁多,且各自有不同的实现,那么我们的工厂去实例化这些产品的时候,必然会有很多代码,毕竟只是一次初始化,为了结构清晰,那么我们就把工厂以产品(对象)为单位,拆分出不同的工厂来。为每个产品定义一个创造者, 然后由调用者自己去选择与哪个工厂方法关联

    code

    代码还是在原来的基础上进行修改,显而易见,把原来的工厂修改成AD工厂加AP工厂

    private static class ADHeroFactory extends AbsHeroFactory {
    
        @Override
        public <HERO extends IHero> HERO createHero() {
            return (HERO) new LuBan();
        }
    }
    
    private static class APHeroFactory extends AbsHeroFactory {
    
        @Override
        public <HERO extends IHero> HERO createHero() {
            return (HERO) new XiaoQiao();
        }
    }
    

    因为每一个对应的产品(对象)已经有了对应的工厂,所以工厂的抽象类还需要稍微的改动,去掉指定类型的参数了

    private abstract static class AbsHeroFactory {
        public abstract <HERO extends IHero> HERO createHero();
    }
    

    main跑一下

    public static void main(String[] args) {
        IHero luBan = new ADHeroFactory().createHero();
        System.out.println(luBan.toString());
        luBan.attack();
        IHero xiaoQiao = new APHeroFactory().createHero();
        System.out.println(xiaoQiao.toString());
        xiaoQiao.attack();
    }
    
    

    运行结果还是和之前一样,只是写法变了,说白了就是为每个产品定义一个创造者,然后由调用者自己去选择与哪个工厂方法关联。

    每一个产品类都对应了一个创建类,好处就是创建类的职责清晰,而且结构简单,但是给可扩展性和可维护性带来了一定的影响如果要扩展一个产品类,就需要建立一个相应的工厂类,这样就增加了扩展的难度。因为工厂类和产品类的数量相同,维护时需要考虑两个对象之间的关系,在复杂的应用中一般采用多工厂的方法,然后再增加一个协调类,避免调用者与各个子工厂交流, 协调类的作用是封装子工厂类, 对高层模块提供统一的访问接口。

    相关文章

      网友评论

          本文标题:创建型-工厂方法(Factory Method)

          本文链接:https://www.haomeiwen.com/subject/ybotyktx.html