作者 点先生 日期 2018.9.26

唠个嗑

先给各位观众老爷道个歉,在上一篇文章的末尾本来说了这次要给大家分享代理模式,但是臣妾,做不到啊! 最近公司给我了一个新项目,于是比较忙一点,再加上代理模式那边的东西有点多,我有点懵逼的,静态、动态、远程、虚拟,还有个RMI,小机灵鬼儿的脑袋一时间处理不过来啊!

最近在搭建新项目的时候,参考了前辈的一些代码。这一次看别人代码的时候,更容易知道别人写着类的目的是干嘛,为啥要这样写了,这就是学习设计模式之后的好处之一吧,我仍然会继续加油。尝到了一些甜头,现在更有动力了。你们的留言,讨论,点赞更是我巨大的动力。

虽然是中途改道来写工厂模式,但绝对不会让各位观众老爷失望的!本次要讲的是三种工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式),以及相关模式源码上的一些理解、扩展。

什么是工厂模式

new!
准确的说,是代替new实例化具体类的一种模式。 接下来我将以“音乐厂牌创造音乐”为例子,由浅到深深入工厂模式。
至于为什么要用工厂模式我会边讲例子边说。

简单工厂模式

制作一首歌曲,确定歌曲风格之后,就先要写词谱曲,然后依次就是录歌,剪辑,混音,就可以发型了。当然也可以“不混,直接发”!Skr~。

public class MusicLabel {Song createSong(String type){Song song = null;if(type.equals("folk")){ song = new FolkSong();}else if(type.equals("rock")){song = new RockSong();}else if(type.equals("pop")){song = new PopSong();}song.prepare();//作词作曲演奏song.Sing(); //录歌song.Cut(); //剪辑song.Mix(); //混音return song;}
}
复制代码

这样写,有没有问题? 没有! 不出bug能跑就完事儿了。科科。
然而这样却违反了开闭原则:对扩展开放,对修改关闭
我们可以把易变化的部分跟不变化的部分分开。也就是将new对象的部分提出来,单独形成一个类(工厂)。

public class SongFactory {public Song orderSong(String type){Song song = null;if(type.equals("folk")){song = new FolkSong();}else if(type.equals("rock")){song = new RockSong();}else if(type.equals("pop")){song = new PopSong();}return song;}
}
复制代码

在这儿有另外一种方法:利用静态方法定义一个简单工厂(静态工厂)。
这样就不需要使用创建对象的方法来实例化对象。但这样也有一个缺点:不能通过继承来改变创建方法的行为。

修改之后重写MusicLabel类

public class MusicLabel {SongFactory factory;public MusicLabel(SongFactory factory) {this.factory = factory;}Song createSong(String type){Song song = null;song = factory.orderSong(type);song.prepare();song.Sing();song.Cut();song.Mix();return song;}
}
复制代码

这样一来就将面向具体编程,变成了面向接口编程。

在设计模式中,“实现一个接口”泛指“实现某个超类型(类/接口)的某个方法”。

心得

给我的感觉,简单工厂模式更像是一种编程的习惯。最简单的解耦,使得工厂类能够被各种厂牌反复使用。
在我还没认识简单工厂之前,其实我就写过很多简单工厂的例子了。各种基类BaseActivity、BaseFragment等等通常都会用到简单工厂模式。
优点: 简单,解耦。
缺点: 静态工厂无法继承,违反开闭原则。

工厂方法模式

定义

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

类图

工厂方法模式有四个核心类:

  1. Product(产品类):所有产品必须实现这个共同的接口,这样使用这些产品的类就可以引用这个接口,而不是具体类。
  2. ConcreteProduct(具体产品类)
  3. Creator(创建者类):实现了所有操纵产品的方法,但不实现工厂方法。
  4. ConcreteCreator(具体创建者类):实现了factoryMethod(),负责创建一个或多个具体产品,只有ConcreteCreator类知道如何创建这些产品。

来撸代码

刚刚我们已经创建了两个类,MusicLabel和SongFactory,MusicLabel在工厂方法中可以作为一个Creator。SongFactory不在四大核心之内,先不管。
我们先来创造一下产品类和创建者类(他们是两个平行类层级)。

public abstract class MusicLabel {Song createSong(String type){Song song = null;song = orderSong(type);song.prepare();song.Sing();song.Cut();song.Mix();return song;}abstract Song orderSong(String type); //工厂方法
}
复制代码
public abstract class Song {String singer;//演唱者String lyricist;//作词人String composer;//作曲人String prepare() {return "演唱者:"+singer + ",作词人:"+lyricist + ",作曲人:"+composer;}String Sing(){return "录歌";}String Cut(){return "剪切";}String Mix(){return "混音";}
}
复制代码

接下来创建各自的子类。厂牌方面,各位最熟知的可能就是“摩登天空”了,另外,听国摇的小伙伴对谢天笑这个名字应该不会陌生,谢天笑是在“十三月”音乐厂牌。这里我们就以这两个厂牌为例,来写各自的子类。

摩登天空音乐厂牌

public class MDSkyMusicLabel extends MusicLabel {@OverrideSong orderSong(String type) { //此处可用简单工厂模式if(type.equals("folk")){return new MDSkyFolkSong();}else if(type.equals("rock")){return new MDSkyRockSong();}else if(type.equals("pop")){return new MDSkyPopSong();}else return  null;}
}
复制代码

十三月音乐厂牌

public class ThirteenMonthMusicLabel extends MusicLabel {@OverrideSong orderSong(String type) { //此处可用简单工厂模式if(type.equals("folk")){return new ThirteenMonthFolkSong();}else if(type.equals("rock")){return new ThirteenMonthRockSong();}else if(type.equals("pop")){return new ThirteenMonthPopSong();}else return  null;}
}
复制代码

在MusicLabel类的createSong()中,并不知道真正创建的是哪一个厂牌的音乐。创建具体对象的工作,都在子类中。
接下来的工作就是把刚刚写过的MDSkyFolkSong等具体子类继承Song。这里只写一个。

public class MDSkyFolkSong extends Song {public MDSkyFolkSong() {singer = "摩登天空的民谣艺人";lyricist = "摩登天空的民谣作词人";composer = "摩登天空的民谣作曲人";}
}
复制代码

在这里或许许多小伙伴要说这样写会有很多子类,很麻烦。但这样已经是最优的选择了。耦合度低,遵守了开闭原则。

感受

工厂方法模式有点像简单工厂的合集,特别是当只有一个具体工厂类存在时。
简单工厂可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。
优点: 在简单工厂的优点上加上“可以变更正在创建的产品”。
缺点: 子类相当多,不便于管理。

抽象工厂模式

刚刚我们再写具体厂牌的时候,有提到,可以在具体厂牌类中使用简单工厂模式。也就是说,我们可以创建MDSkySongFactory和ThirteenMonthSongFactory两个工厂类。并且这两个工厂做的事都是一样的,只是具体东西不一样而已。
那……
我们是不是可以写一个工厂超类,把要做的事情写成抽象方法,再让子工厂类各自实现呢?
可以的!这就是传说中的抽象工厂模式。

定义

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

类图

  1. Cilent(客户类):代码中只需涉及抽象工厂,运行时自动使用实际的工厂。
  2. AbstractFactory(抽象工厂):定义了一个接口,所有具体工厂必须实现它。这个接口包含了一组方法来生产产品。
  3. ConcreteFactory(具体工厂):客户只需要使用其中一个工厂而不需要实例化任何产品对象。
  4. AbstractProduct(抽象产品类):这些抽象产品类就是抽象工厂中所需要的每一个条件。
  5. ConcreteProduct(具体产品类):继承抽象产品类。

由入门到放弃

刚刚我们说过,我们可以整理一个工厂超类,这个工厂超类,就是AbstractFactory!它在我们这个例子中的作用就是返回一个singer,一个lyricist和一个composer。所以我们可以这样写。

public interface SongFactory {public String findSinger();public String findLyricist();public String findComposer();
}
复制代码

然后给每个厂牌都写一个具体工厂

public class MDskySongFactory implements SongFactory {@Overridepublic String findSinger() {return new MDskySinger();}@Overridepublic String findLyricist() {return new MDskyLyricist();}@Overridepublic String findComposer() {return new MDskyComposer();}
}
复制代码
public class ThirteenMonthSongFactory implements SongFactory {@Overridepublic String findSinger() {return new ThirteenMonthSinger();}@Overridepublic String findLyricist() {return new ThirteenMonthLyricist();}@Overridepublic String findComposer() {return new ThirteenMonthComposer();}
}
复制代码

还需要重写一下Song类

public abstract class Song {String singer;//演唱者String lyricist;//作词人String composer;//作曲人abstract void prepare();//只改变了这个方法String Sing(){return "录歌";}String Cut(){return "剪切";}String Mix(){return "混音";}@Overridepublic String toString() {return "Song{" +"singer='" + singer + '\'' +", lyricist='" + lyricist + '\'' +", composer='" + composer + '\'' +'}';}
}
复制代码

现在就可以根据工厂类来写歌曲子类了。每个厂牌都有FolkSong、RockSong、PopSong,现在不用写那么多子类,只需要建立一个相应子类,材料(作词作曲演唱)就交给传递进去的工厂类来解决!

public class FolkSong extends Song{SongFactory factory;public FolkSong(SongFactory factory) {this.factory = factory;}@Overridevoid prepare() {singer = factory.findSinger();lyricist = factory.findLyricist();composer = factory.findComposer();}
}
复制代码

现在我们几乎完成了所有的材料,就差调用了。现在先来理一理这些东西。

  1. 抽象工厂类是SongFactor。
  2. 具体工厂类是MDskySongFactory 和ThirteenMonthSongFactory。
  3. 抽象产品类是Singer、Lyricist、Composer。
  4. 具体产品类是MDskySinger、ThirteenMonthSinger等。
  5. Client是MDSkyMusicLabel和ThirteenMonthMusicLabel。

现在就在Client里面调用看看吧。

public class MDSkyMusicLabel extends MusicLabel {@OverrideSong orderSong(String type) {Song song = null;SongFactory factory = new MDskySongFactory();if(type.equals("folk")){song = new FolkSong(factory);}else if(type.equals("rock")){song = new RockSong(factory);}else if(type.equals("pop")){song = new PopSong(factory);}return song;}
}
复制代码

完美!到处都充斥着依赖倒置的清香。

体会

这个模式虽然需要些的核心类比较多,但是当需求满足“为相互依赖的对象提供一个接口”,具体对象又比较多,又易修改的时候,这个模式的优点你就能体会到了。
优点: 闭合开闭原则,耦合低。
缺点: 不适用于对象数量少的情况。

BitmapFactory

BitmapFactory是android中比较常见的工厂模式的使用。我们肯定都写过这样一句代码

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher) ;
复制代码

看出来什么没??
这特么就是个简单工厂模式啊!还是个静态工厂!
为何这么说,因为它是通过类名调用方法,并且返回了一个对象。这不就是简单工厂吗?

看里面,全是红彤彤的静态方法。这个工厂做的事就是通过不同的参数,返回Bitmap对象。这也就是简单工厂模式的作用。
今天的源码解读就到此为止了,要问我为啥没写扩展。
你要是看懂了工厂模式,就不会问这个问题。

为什么要用工厂模式

(此处应有弹幕:“收尾呼应,满分作文!”)
我写的优点里面那么多,还不能让你使用工厂模式吗?
就冲解耦合这一点,你就该用它!

总结

以下是我“设计模式系列”文章,欢迎大家关注留言投币丢香蕉。

设计模式入门
Java与Kotlin的单例模式
Kotlin的装饰者模式与源码扩展
由浅到深了解工厂模式

由浅到深了解工厂模式相关推荐

  1. 建造者模式浅谈 与工厂模式的区别

    感谢您的阅读.如果感觉文章对您有用,麻烦您动动手指点个赞,以资鼓励.谢谢! 转载请注明出处哈 建造者模式浅谈 与工厂模式的区别_茄子_土豆的博客-CSDN博客_建造者模式和工厂模式的区别 创建对象时构 ...

  2. 浅谈设计模式之单例模式、适配器模式、抽象工厂模式

    带你读懂几种常见的设计模式 第三弹 本文已经是设计模式系列的第三篇文章了,今天来讲讲单例模式.抽象工厂模式和适配器模式. 1.单例模式 单例模式让一个类最多只有一个实例.具体的做法是: 让类的构造方法 ...

  3. 华山论剑之浅谈iOS的生产线 工厂模式

    工厂模式是一种快速创建大量对象的模式.简单易上手,今天我就谈一下我对工厂模式的理解.工厂模式的核心思想就是继承.子类继承父类的方法并且重写父类方法.下面我们就看一下实际中是如何使用工厂模式的. *** ...

  4. python工厂模式 理解_浅谈Python设计模式 - 抽象工厂模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 在上一篇我们对工厂模式中的普通工厂模式有了一定的了解,其实抽象工作就是 表示针对 ...

  5. 浅谈Java工厂模式

    一. 概念 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的.(工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,虽然这样做 ...

  6. 为什么工厂模式是华而不实的——浅谈工厂模式的利与弊

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17428923 说明:博主虚心接受大家的抨击,批评,指正 前言 我一直想介绍下 ...

  7. 1、从王者荣耀浅谈设计模式(简单工厂模式)

    姓名:简单工厂模式 英文名:factory method Pattern 价值观:容易扩展 王者荣耀的英雄一个个阶段性的上线,有射手.坦克.刺客等等,每个英雄的类型,技能,级别都不一样, 这里主要举个 ...

  8. 浅谈Spring框架应用的设计模式(一)——工厂模式

    文章目录 前言 一.工厂模式介绍 1.简单工厂模式 (1)静态工厂模式 (2)利用反射机制实现的简单工厂 2.工厂方法模式 3.抽象工厂模式 二.Spring框架中工厂模式的重要应用 1.BeanFa ...

  9. 为什么工厂模式是华而不实的—浅谈工厂模式的利与弊

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17428923 说明:博主虚心接受大家的抨击,批评,指正 前言 我一直想介绍下 ...

最新文章

  1. apache压力测试工具ab
  2. 深度操作系统 15 发布 —— 不忘初心,追逐梦想
  3. [zz]volatile
  4. java 列表展开方式_android列表控件实现展开、收缩功能
  5. mysql 三表inner join_MySql的join(连接)查询 (三表 left join 写法)
  6. nginx ---- 背景介绍及环境准备
  7. 微软从 Engine Yard 手中收购容器平台 Deis
  8. 单片机芯片——电子秤芯片
  9. win10的计算机 桌面图标不见了怎么办,Win10我的电脑怎么放在桌面?Win10此电脑图标不见了的解决方法...
  10. 我不想加班,您看我还有机会吗?
  11. h5 php 拍照上传图片,H5拍照、选择图片上传组件核心
  12. 【小学生打字练习软件】_在线网上打字比赛软件系统
  13. 计算机大连理工三年级下册教案,大连理工大学版信息技术三年级上册教案.doc...
  14. 映客直播技术实战:直播平台的数据库架构演变
  15. git小文件时报错Remote origin does not support the LFS
  16. python贪吃蛇论文_爆款游戏《贪吃蛇大作战》的 Python 实现
  17. css3实现各种角度的三角形
  18. 某连续函数的不连续导函数图像绘制(matlab实现)
  19. mac上使用rz、sz命令
  20. ADI Blackfin DSP处理器-BF533的开发详解23:SDRAM内存的设计和自检(含源代码)

热门文章

  1. java多线程构造函数_Java多线程编程经验谈
  2. python怎么检查数据库实例能否链接_python pymysql链接数据库查询结果转为Dataframe实例...
  3. linux 关闭磁盘检测,linux下检测磁盘状态
  4. python日志模块为什么打印到界面_如何将外部模块的日志消息打印到主Python模块的终端窗口?...
  5. php json对象取数据类型,PHP如何科学地json_encode类对象数据
  6. NIO详解(十一):线程间通信管道Pipe
  7. android 上键,在Android键盘上设置Return键
  8. android自定义下载框架,Android_DownloadUtil
  9. 区块链 java 开源_详细介绍Java区块链开源代码背后的内容
  10. redis mysql 案例_linux安装redis和mysql的实例讲解