学习的时候我们可以过度设计,只是为了使用一下设计模式,但是我们在工作中千万不要过度设计,什么东西都不能过度。
工厂系列有2种类设计模式:工厂方法、抽象工厂
但是平时也会有人提到什么简单工厂、静态工厂你强行说这是设计模式也行,模式嘛都是人定义的,但是一般技术上没有把他俩算在设计模式里。
为什么要是用工厂呢,直接new 他不香吗?
因为工厂可以灵活控制生产过程、可以限制权限、记录创建日志、添加修饰等等
想一个故事,带入一下…
话说,有一个小伙子小浪浪,他呢是同龄人中混的比较好的,有房有车有存款。
他呢准备找对象,我们这里定义几种女生类型不同的类型有不同的爱好。
分别是:喜欢脱口秀的、喜欢哲学的、喜欢历史的
我们先创建这几种女生类:
package factory.simple; /** */ public class TalkShowGirl { public void love(){ System.out.println("喜欢脱口秀"); } }
package factory.simple; /** */ public class PhilosophyGirl { public void love(){ System.out.println("喜欢哲学"); } }
package factory.simple; /** */ public class HistoryGirl { public void love(){ System.out.println("喜欢历史"); } }
然后小浪浪开始思考自己喜欢哪种:
package factory.simple; /** */ public class TestDemo { public static void main(String[] args) { // 刚开始准备找个喜欢脱口秀的 TalkShowGirl girl = new TalkShowGirl(); girl.love(); // 男人嘛朝三暮四 后来想找个喜欢哲学的 PhilosophyGirl girlp = new PhilosophyGirl(); girlp.love(); // 最后觉得还是找个喜欢历史的吧 HistoryGirl girlh = new HistoryGirl(); girlh.love(); } }
上边这种写法就是最原始的写法,自己想要什么就自己去new,这也是程序员经常开玩笑说的一句话:
没对象? 自己new 一个呀 !!
尴尬又不失礼貌的漏出想弄死对方的心情。
上边说了,简单工厂能真正意义上说是一种设计模式,但是这也是一种把new对象动作整合的一种方式
这时候来了一个媒婆,媒婆跟小浪浪说了,你想要什么直接给我说,我给你找就可以。
对于媒婆来说给小浪浪找的都是姑娘(小浪浪暂时没啥问题,还是比较喜欢小姐姐多一些)
所以这时候姑娘需要抽象出一个概念来
package factory.simple; /** */ public interface Girl { void love(); }
那三中类型的姑娘都需要实现这个接口,也就是说虽然他们有不同的爱好,但是他们始终是个姑娘
package factory.simple; /** */ public class TalkShowGirl implements Girl { @Override public void love(){ System.out.println("喜欢脱口秀"); } } //----------------------------------------------------------- package factory.simple; /** */ public class PhilosophyGirl implements Girl { @Override public void love(){ System.out.println("喜欢哲学"); } } //------------------------------------------------------------- package factory.simple; /** */ public class HistoryGirl implements Girl { @Override public void love(){ System.out.println("喜欢历史"); } }
媒婆类:
媒婆类其实就脱离了创建者,也就是脱离了小浪浪,媒婆可以在给小浪浪介绍姑娘之前先对姑娘进行一些个操作。
比如:化化妆、教她一些该说不该说的话、媒婆自己记录一下这个姑娘已经给多少人介绍过了等等。
package factory.simple; /** */ public class SimpleFactory { public Girl find(String type) throws Exception { if (type == null || "".equals(type)) { throw new Exception("你什么也不说,我也没办法呀!!"); } //jdk1.7开始switch支持String了 type不能为null 否则会报空指针异常 switch (type) { case "history": // 工厂的好处就是 在创建之前可以随意加代码 也可以对HistoryGirl进行包装 // 比如媒婆给小姑娘化个妆 return new HistoryGirl(); case "talkshow": return new TalkShowGirl(); case "philosophy": return new PhilosophyGirl(); default: throw new Exception("你要的可真多,我没有,滚!"); } } }
有了媒婆之后,小浪浪再找对象流程就变成这样了:
package factory.simple; /** */ public class TestDemo02 { public static void main(String[] args) throws Exception { // 请媒婆出山 SimpleFactory factory = new SimpleFactory(); // 刚开始准备找个喜欢脱口秀的 Girl girl = factory.find("talkshow"); girl.love(); // 男人嘛朝三暮四 后来想找个喜欢哲学的 Girl girlp = factory.find("philosophy"); girlp.love(); // 最后觉得还是找个喜欢历史的吧 Girl girlh = factory.find("history"); girlh.love(); // 过了段时间想要一个身材妖娆的 媒婆直接翻脸 让他滚 Girl girls = factory.find("身材妖娆"); girls.love(); } }
静态工厂就是媒婆电话公告天下,不用请媒婆出山,直接电话联系就能搞定
package factory.simple; /** */ public class SimpleStaticFactory { public static Girl find(String type) throws Exception { if (type == null || "".equals(type)) { throw new Exception("你什么也不说,我也没办法呀!!"); } //jdk1.7开始switch支持String了 type不能为null 否则会报空指针异常 switch (type) { case "history": return new HistoryGirl(); case "talkshow": return new TalkShowGirl(); case "philosophy": return new PhilosophyGirl(); default: throw new Exception("你要的可真多,我没有,滚!"); } } } // 让媒婆找对象就直接 SimpleStaticFactory.find("xxxx")
这个才是真正的被收纳到23中设计模式的其中一种
随着互联网发展,出来一个一个概念叫垂直领域,媒婆也与时俱进了,不同爱好的姑娘有不同的媒婆负责接洽。
你想找喜欢历史的姑娘,你就要找到负责喜欢历史姑娘的媒婆,如果你找别的媒婆那给你介绍的可不一定是你喜欢的哦。
其实就是各司其职:简单工厂违反了“开闭原则” (对修改关闭,对扩展开放),因为你要加一种类型的姑娘,你就需要修改媒婆的记事本SimpleFactory
这时候需要很多媒婆了,各种类型的媒婆都叫媒婆,所以他们应该有一个抽象接口(抽象类也可以)
package factory.simple; // 抽象的媒婆 public interface Factory { Girl find(); } //------------------------------ package factory.simple; // 掌握喜欢脱口秀姑娘名单的媒婆 public class TalkShowFactory implements Factory{ @Override public Girl find(){ return new TalkShowGirl(); } } //-------------------------------- package factory.simple; // 掌握喜欢哲学的姑娘名单的媒婆 public class PhilosophyFactory implements Factory{ @Override public Girl find(){ return new PhilosophyGirl(); } } //-------------------------------- package factory.simple; // 掌握喜欢历史的姑娘名单的媒婆 public class HistoryFactory implements Factory{ @Override public Girl find(){ return new HistoryGirl(); } }
这个时候小浪浪再找对象就需要根据自己的要求去找不同的媒婆了:
package factory.simple; /** */ public class TestDemo03 { public static void main(String[] args) { // 刚开始准备找个喜欢脱口秀的 Factory mp = new TalkShowFactory(); Girl girl = mp.find(); girl.love(); // 男人嘛朝三暮四 后来想找个喜欢哲学的 Factory mpp = new PhilosophyFactory(); Girl girlp = mpp.find(); girlp.love(); // 最后觉得还是找个喜欢历史的吧 Factory mph = new HistoryFactory(); Girl girlh = mph.find(); girlh.love(); } }
这个时候如果小浪浪想找一个纯欲类型女生,我们不需要修改之前的三中类型媒婆,我们面向扩展开放,新建一种类型媒婆即可
package factory.simple; public class SimpleSexyGirl implements Girl{ @Override public void love() { System.out.println("哥哥,我美吗~"); } }
package factory.simple; // 掌握纯欲姑娘信息的媒婆 public class SimpleSexyFactory implements Factory{ @Override public Girl find(){ return new SimpleSexyGirl(); } }
这就是面向扩展开放,我们新增的类型,不会影响之前的代码
挠挠头,想想这个故事怎么强行适配一下抽象工厂。。
思考中…
抽象工厂模式为创建一组对象提供解决方案。与工厂方法模式相比,抽象工厂模式的具体工厂不只是创建一种产品,他负责创建一族产品
是这样的,小浪浪虽然很优秀,但是他很懒,他让媒婆介绍对象的时候,还让媒婆把见面地点和去见面地点的交通方式都给安排好了。
这个时候媒婆的职责就变多了:安排相亲姑娘、安排见面地点、安排出行交通方式‘
我们画一个简单的图(千万不要迷失在网上那些看似很严谨又很专业的图中)
package factory.abstractfactorytest.girl; public interface Girl { void love(); } //------------哲学------------ package factory.abstractfactorytest.girl; public class PhilosophyGirl implements Girl { @Override public void love() { System.out.println("喜欢哲学"); } } //--------纯欲------------------- package factory.abstractfactorytest.girl; public class SimpleSexyGirl implements Girl { @Override public void love() { System.out.println("哥哥,我美吗~"); } }
见面地点:
package factory.abstractfactorytest.address; public interface Address { void where(); } //---------图书馆----------- package factory.abstractfactorytest.address; public class BookAddress implements Address{ @Override public void where() { System.out.println("图书馆见面"); } } //-----------宾馆----------------- package factory.abstractfactorytest.address; public class HotelAddress implements Address{ @Override public void where() { System.out.println("宾馆见面"); } }
见面出行方式:
package factory.abstractfactorytest.travelmodel; public interface TravelModel { void run(); } //----------开法拉利------------------- package factory.abstractfactorytest.travelmodel; public class FerrariTravelModel implements TravelModel{ @Override public void run() { System.out.println("开法拉利去见面"); } } //-----------步行去------------------ package factory.abstractfactorytest.travelmodel; public class WalkTravelModel implements TravelModel{ @Override public void run() { System.out.println("走着去见面"); } }
媒婆:
package factory.abstractfactorytest; import factory.abstractfactorytest.address.Address; import factory.abstractfactorytest.girl.Girl; import factory.abstractfactorytest.travelmodel.TravelModel; public abstract class AbstractFactory { // 找女孩 abstract Girl find(); // 找见面地点 abstract Address address(); // 找出行方式 abstract TravelModel travelModel(); } //------------------- 媒婆一号 哲学+图书馆+步行 package factory.abstractfactorytest; import factory.abstractfactorytest.address.Address; import factory.abstractfactorytest.address.BookAddress; import factory.abstractfactorytest.girl.Girl; import factory.abstractfactorytest.girl.PhilosophyGirl; import factory.abstractfactorytest.travelmodel.TravelModel; import factory.abstractfactorytest.travelmodel.WalkTravelModel; public class Factory01 extends AbstractFactory{ // 哲学女孩 @Override public Girl find() { return new PhilosophyGirl(); } // 图书馆 @Override public Address address() { return new BookAddress(); } // 步行见面 @Override public TravelModel travelModel() { return new WalkTravelModel(); } } //------------------ 媒婆二号 纯欲+宾馆+法拉利 package factory.abstractfactorytest; import factory.abstractfactorytest.address.Address; import factory.abstractfactorytest.address.HotelAddress; import factory.abstractfactorytest.girl.Girl; import factory.abstractfactorytest.girl.SimpleSexyGirl; import factory.abstractfactorytest.travelmodel.FerrariTravelModel; import factory.abstractfactorytest.travelmodel.TravelModel; public class Factory02 extends AbstractFactory{ //纯欲女孩 @Override public Girl find() { return new SimpleSexyGirl(); } // 宾馆 @Override public Address address() { return new HotelAddress(); } // 开法拉利见面 @Override public TravelModel travelModel() { return new FerrariTravelModel(); } }
小浪浪找对象:
package factory.abstractfactorytest; import factory.abstractfactorytest.address.Address; import factory.abstractfactorytest.girl.Girl; import factory.abstractfactorytest.travelmodel.TravelModel; /** */ public class Test { public static void main(String[] args) { // 找了个媒婆给介绍对象 媒婆给组合了一套 AbstractFactory ab = new Factory01(); Girl girl01 = ab.find(); Address address01 = ab.address(); TravelModel travelModel01 = ab.travelModel(); girl01.love(); address01.where(); travelModel01.run(); // 上一个没有满意 又想换一个 System.out.println("======================换一个"); AbstractFactory ab2 = new Factory02(); Girl girl02 = ab2.find(); Address address02 = ab2.address(); TravelModel travelModel02 = ab2.travelModel(); girl02.love(); address02.where(); travelModel02.run(); } } 输出结果: 喜欢哲学 图书馆见面 走着去见面 ======================换一个 哥哥,我美吗~ 宾馆见面 开法拉利去见面
设计模式是用来帮助我们写更漂亮的代码,而不是让我们来写更别扭的代码。
千万不能为了设计而设计,我的朋友小浪浪曾经说过我,你这样写就是过度设计。
有时候过度设计不仅费脑子而且还费时间