第三篇 工厂模式之工厂方法模式思疑自释

工厂模式之工厂方法模式思疑自释

在学习简单工厂模式和工厂方法模式时,我如同大多数朋友一样发出了以下质疑:
  1. 工厂方法模式真的解决了简单工厂中违背开闭原则(OCP)的缺点?
  2. 继承工厂父类或实现了工厂接口的子类,在后期新增的时候,使用方不还是需要修改代码,才能新增一个种类?
经过一番思考后,我决定用一个比较梦幻的例子来说明我对工厂方法模式的理解。希望通过这个例子,能够给大家带来一些启发!

工厂方法模式之梦幻的猫工厂

我们都知道,无论什么东西,放久了都会长猫(伪)( ̄y▽ ̄)*捂嘴偷笑
其实每一个会长猫的东西,都是继承了梦幻猫工厂的力量(伪)( ̄y▽ ̄)*继续捂嘴偷笑(下次不笑了,笑的太丑会被打!)
先见识一下梦幻的猫工厂:
/*梦幻的猫咪生产工厂*/
/*第一种:接口方式*/
public interface CatFactory {

    /*梦幻的能力:长猫*/
    Cat growCat();
}

/*第二种:抽象类方式*/
public abstract CatFactory {

    /*梦幻的能力:长猫*/
    abstract Cat growCat();
}
长得并不梦幻,但重要的是它有梦幻的力量:长猫。
继承这种梦幻能力的圣物种类当然不多,但众所周知,猫盒子和猫架子继承了这种力量。
梦幻的猫盒子:
/*具有梦幻猫工厂能力的神奇盒子*/
public class CatBox implements CatFactory{

    public CatBox(){
        System.out.println("您摆了一个猫盒子~很久以后~");
    }

    @Override
    public Cat growCat() {
        //梦幻的猫盒子只能长出布偶猫
        return new Ragdoll(); 
    }
}
梦幻的猫架子:
/*具有梦幻猫工厂能力的神奇架子*/
public class CatShelf implements CatFactory {

    public CatShelf(){
        System.out.println("您放了一件猫架子~很久以后~");
    }

    @Override
    public Cat growCat() {
        //梦幻的猫架子只能长出挪威森林猫
        return new NorwegianForestCat();
    }
}
布偶猫和森林猫,它们都是喵星人~
喵星人种族:
public abstract class Cat {
    
    /*喵喵叫*/
    public abstract void mewing();

    /*呼噜叫*/
    public abstract void purring();
}
布偶猫:
/*布偶猫*/
public class Ragdoll extends Cat {

    public Ragdoll(){
        System.out.println("叮叮叮~您收获了一只小仙女布偶猫!");
    }

    @Override
    public void mewing() {
        System.out.println("小仙女一直很安静,偶尔喵喵喵~");
    }

    @Override
    public void purring() {
        System.out.println("小仙女一直很安静,偶尔呼呼呼~");
    }
}
森林猫:
/*挪威森林猫*/
public class NorwegianForestCat extends Cat {

    public NorwegianForestCat(){
        System.out.println("咚咚咚~您收获了一只挪威妖精森林猫!");
    }

    @Override
    public void mewing() {
        System.out.println("森林里的妖精,发出喵喵的空音~");
    }

    @Override
    public void purring() {
        System.out.println("外表是妖精,打呼却如同中年大叔一般,呼噜呼噜~");
    }
}
某一天,我在野外打Boss,掉落了圣物猫盒子,并将其带回了家,摆在家中:
public class MineCat {
    public static void main(String[] args) {
        /*摆了一个猫盒子*/
        CatFactory catFactory = new CatBox();
        Cat cat = catFactory.growCat();
        cat.mewing();
        cat.purring();
}
然后:
您摆了一个猫盒子~很久以后~
叮叮叮~您收获了一只小仙女布偶猫!
小仙女一直很安静,偶尔喵喵喵~
小仙女一直很安静,偶尔呼呼呼~
又一天,我在地下城打Boss,掉落了圣物猫架子子,并将其带回了家,放置在家中:
public class MineCat {
    public static void main(String[] args) {
        /*摆了一个猫盒子*/
        CatFactory catFactory = new CatBox();
        Cat cat = catFactory.growCat();
        cat.mewing();
        cat.purring();

        System.out.println("\n-------------这只是一个分割线-----------\n");
        /*放了一件猫架子*/
        catFactory = new CatShelf();
        cat = catFactory.growCat();
        cat.mewing();
        cat.purring();
    }
}
然后:
您摆了一个猫盒子~很久以后~
叮叮叮~您收获了一只小仙女布偶猫!
小仙女一直很安静,偶尔喵喵喵~
小仙女一直很安静,偶尔呼呼呼~

-------------这只是一个分割线-----------

您放了一件猫架子~很久以后~
咚咚咚~您收获了一只挪威妖精森林猫!
森林里的妖精,发出喵喵的空音~
外表是妖精,打呼却如同中年大叔一般,呼噜呼噜~

-------------这只是一个分割线-----------
从上面的两件圣物可以看出,梦幻猫工厂的能力本身,是不知道会长出什么猫的,也不会去长猫。
猫的实例化被推迟到了,继承了梦幻猫工厂能力的猫盒子和猫架子上。
如此这般,便完成了工厂方法模式的实现。

但是,有一天,我在天空城又打到了一件具有梦幻猫工厂能力的圣物:猫树苗。
而猫树苗的能力是长出狸花猫。
梦幻的猫树苗:
/*具有梦幻猫工厂能力的神奇树苗*/
public class CatTree implements CatFactory {

    public CatTree(){
        System.out.println("您种了一棵猫树苗~很久以后~");
    }

    @Override
    public Cat growCat() {
        return new DragenLi();
    }
}
狸花猫:
/*中国狸花猫*/
public class DragenLi extends Cat {

    public DragenLi(){
        System.out.println("哒哒哒~您收获了一只中华龙狸狸花猫!");
    }

    @Override
    public void mewing() {
        System.out.println("虽然被叫做龙狸,但撒娇时还是喵喵喵~");
    }

    @Override
    public void purring() {
        System.out.println("打呼的呼噜声,才发现不大的身体内隐藏着龙魂,吼呼呼~吼呼呼~");
    }
}
这时候,我还是将猫树苗带回了家:
public class MineCat {
    public static void main(String[] args) {
        /*摆了一个猫盒子*/
        CatFactory catFactory = new CatBox();
        Cat cat = catFactory.growCat();
        cat.mewing();
        cat.purring();

        System.out.println("\n-------------这只是一个分割线-----------\n");
        /*放了一件猫架子*/
        catFactory = new CatShelf();
        cat = catFactory.growCat();
        cat.mewing();
        cat.purring();

        System.out.println("\n-------------这只是一个分割线-----------\n");
        /*种了一棵猫树苗*/
        catFactory = new CatTree();
        cat = catFactory.growCat();
        cat.mewing();
        cat.purring();
    }
}
然后:
您摆了一个猫盒子~很久以后~
叮叮叮~您收获了一只小仙女布偶猫!
小仙女一直很安静,偶尔喵喵喵~
小仙女一直很安静,偶尔呼呼呼~

-------------这只是一个分割线-----------

您放了一件猫架子~很久以后~
咚咚咚~您收获了一只挪威妖精森林猫!
森林里的妖精,发出喵喵的空音~
外表是妖精,打呼却如同中年大叔一般,呼噜呼噜~

-------------这只是一个分割线-----------

您种了一棵猫树苗~很久以后~
哒哒哒~您收获了一只中华龙狸狸花猫!
虽然被叫做龙狸,但撒娇时还是喵喵喵~
打呼的呼噜声,才发现不大的身体内隐藏着龙魂,吼呼呼~吼呼呼~
这时候,开头的两个疑问便产生了。
不是不违背开闭原则吗?
不是不需要修改代码吗?
其实,我觉得大多数人,是被main方法这个例子误导了!

正真重要的是下面三行代码之后所包含的设计思想:

cat = catFactory.growCat();
cat.mewing();
cat.purring();
Cat类和CatFactory并没发生源代码的修改,我们只是扩展了它们的DragenLi子类和CatTree子类。
而至于猫盒子、猫架子、猫树苗,我是如何知道要给梦幻猫工厂的?
答:这里有一个本质的思想误区。不是我知道他们有长猫的能力,而是因为他们本身就有长猫的能力。

以Web开发的思想,来说明:
页面上原本有猫盒子和猫架子两个按钮,这两个按钮是通过后台数据库配置的。
某一天,梦幻世界的大神——数据库管理员——决定追加一个梦幻道具,猫树苗。
这时候,浏览器没有重装,HTML页面代码没有修改,但页面上却已经显示了第三个圣物。
而main方法则替换为请求调用的方法:
@ResponseBody
@RequestMapping("/holyThings")
public String holyThings(CatFactory catFactory){
    Cat cat = catFactory.growCat();
    cat.mewing();
    cat.purring();
    return "得到一只猫";
}
这样,无论是通过拦截器还是反射来实现catFactory对象的传入,最终结果就是,当我点击某个按钮时,后台便已经知道它需要的是CatFactory类的哪个子类。

至此,关于工厂方法类的思疑自释便梦幻的结束了!
顺便一提:工厂方法模式最大的缺点就是,需要新增许多的工厂子类才能完成新的工厂产物管理。系统会耗费大量的资源去管理各种工厂子类,造成资源的耗费。

笔者话:知识的理解深度,随着每一位朋友对知识的运用而有所不同。达者为师!若在下所说内容中有缺漏或错误,还望指正!由衷感谢!

互促互进,常学常新!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值