学习的时候我们可以过度设计,只是为了使用一下设计模式,但是我们在工作中千万不要过度设计,什么东西都不能过度。
工厂系列有2种类设计模式:工厂方法、抽象工厂
但是平时也会有人提到什么简单工厂、静态工厂你强行说这是设计模式也行,模式嘛都是人定义的,但是一般技术上没有把他俩算在设计模式里。
为什么要是用工厂呢,直接new 他不香吗?
因为工厂可以灵活控制生产过程、可以限制权限、记录创建日志、添加修饰等等
一、故事起源
想一个故事,带入一下...
话说,有一个小伙子小浪浪,他呢是同龄人中混的比较好的,有房有车有存款。
他呢准备找对象,我们这里定义几种女生类型不同的类型有不同的爱好。
分别是:喜欢脱口秀的、喜欢哲学的、喜欢历史的
我们先创建这几种女生类:
package factory.simple;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
public class TalkShowGirl {
public void love(){
System.out.println("喜欢脱口秀");
}
}
package factory.simple;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
public class PhilosophyGirl {
public void love(){
System.out.println("喜欢哲学");
}
}
package factory.simple;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
public class HistoryGirl {
public void love(){
System.out.println("喜欢历史");
}
}
然后小浪浪开始思考自己喜欢哪种:
package factory.simple;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
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;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
public interface Girl {
void love();
}
那三中类型的姑娘都需要实现这个接口,也就是说虽然他们有不同的爱好,但是他们始终是个姑娘
package factory.simple;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
public class TalkShowGirl implements Girl {
@Override
public void love(){
System.out.println("喜欢脱口秀");
}
}
//-----------------------------------------------------------
package factory.simple;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
public class PhilosophyGirl implements Girl {
@Override
public void love(){
System.out.println("喜欢哲学");
}
}
//-------------------------------------------------------------
package factory.simple;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
public class HistoryGirl implements Girl {
@Override
public void love(){
System.out.println("喜欢历史");
}
}
媒婆类:
媒婆类其实就脱离了创建者,也就是脱离了小浪浪,媒婆可以在给小浪浪介绍姑娘之前先对姑娘进行一些个操作。
比如:化化妆、教她一些该说不该说的话、媒婆自己记录一下这个姑娘已经给多少人介绍过了等等。
package factory.simple;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
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;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
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;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
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;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
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;
/**
* @author 发现更多精彩 关注公众号:木子的昼夜编程
*/
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();
}
}
输出结果:
喜欢哲学
图书馆见面
走着去见面
======================换一个
哥哥,我美吗~
宾馆见面
开法拉利去见面
六、唠唠
设计模式是用来帮助我们写更漂亮的代码,而不是让我们来写更别扭的代码。
千万不能为了设计而设计,我的朋友小浪浪曾经说过我,你这样写就是过度设计。
有时候过度设计不仅费脑子而且还费时间
欢迎关注公众号:木子的昼夜编程