【秒懂设计模式】总述及工厂模式
秒懂设计模式——总述及工厂模式
【前言】每次一说道“设计模式”总会给人一种误区,认为这些东西,只有那些“技术大牛”才会玩的东西。但是给我的感觉却恰恰相反,它更应该是“非牛人”玩的东西。为什么这么说呢?打个比方吧,“设计模式”就好比武术中的“固定招式”,只有新手会有板有眼,一招一式的照着做,而那些真正的武林高手,都是“无招胜有招”的。当这些东西烂熟于心,得心应手时,对这些所谓的设计模式,都会达到一种“司空见惯”式的“视而不见”,一切都会变得水到渠成,自然而然的流露。
还是我那句口头禅,既然我这个设计模式,定义为“秒懂”系类,自然是“很简单的”,我会用最直白甚至低俗的例子及图画,来给大家一一剖析。当然,可能会有些你认为是谬论的地方,觉得玷污你心中高雅的知识,请看到这里,点击右上角关闭网页。我个人始终有个观点:当高深到达了“俗不可耐”的程度,才能叫做真正的“大悟大彻”!
(一)总述
1.什么是设计模式?
【官方定义】设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。
【理解】它就是一套前人们的总结,可以理解为经验公式。
2.设计模式有什么用?
【官方定义】使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。
【理解】经验公式的好处就是让你可以直接套用,大家都懂,省事还靠谱(因为前人已经验证过了)。
3.设计模式的六大原则?
①开闭原则(Open Close Principle)
【简记】对扩展开放,对修改关闭。
【理解】像插座,插孔不够用了,你可以再接一个插排(扩展),但是你不能在原插座上直接钻两个孔吧(修改)?
②里氏代换原则(Liskov Substitution Principle)
【简记】任何基类可以出现的地方,子类一定可以出现。
【理解】能用插座(基类)的地方,就一定可以用再接一个插排(子类)代替。
③依赖倒转原则(Dependence Inversion Principle)
【简记】依赖于抽象而不依赖于具体。
【理解】想用电,最终依赖的是插座(抽象)吧,不能依赖于插排(具体),万一你手头有插排,但是公寓没插座也没用啊。
④接口隔离原则(Interface Segregation Principle)
【简记】使用多个隔离的接口,比使用单个接口要好。同时降低类之间的耦合度。
【理解】不要把所有的插排,都擦在一个插座上。
⑤迪米特法则,又称最少知道原则(Demeter Principle)
【简记】一个实体应当尽量少地与其他实体之间发生相互作用,尽量相对独立。作用也是解耦合。
【理解】“达康书记”(实体)在工作及生活中,很独立,极少与亲朋好友(其它实体)互相作用,以至于妻子出事了,也没影响到自己的政治生涯(因为耦合度低)。
⑥合成复用原则(Composite Reuse Principle)
【简记】合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。
(二)工厂模式
工厂模式属于创建型模式,目的为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,提高灵活性。
工厂模式在《Java 与模式》中分为三类(从上到下越来越抽象):
①简单工厂模式(Simple Factory)[又称静态工厂方法模式]
②工厂方法模式(Factory Method)
③抽象工厂模式(Abstract Factory)
下面注意介绍:
1.简单工厂模式(又称静态工厂方法模式)
【讲故事】某思聪,富二代喜欢豪车,开始告诉手下“给我打造一辆奔驰车”,过几天嫌档次不够,又说“给我打造一辆宝马车”,结果还不知足,又说“给我打造一辆玛莎拉蒂”....周而复始,他的属下发现很麻烦,于是给他创建一个“车场”。以后,某思聪想换车,只说名字就行了。
【意图】定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类。
【Java代码】
①创建一个抽象产品角色
package com.liyan.factory; /*** 创建一个抽象产品角色* <p>Title: Car</p> * @author Liyan * @date 2017年4月26日 下午1:55:22*/ public interface Car {/*** 抽象的创建车方法* <p>Title: creatCar</p> * @author Liyan * @date 2017年4月26日 下午1:58:04 */public void creatCar(); }
②创建奔驰具体产品角色
package com.liyan.factory; /*** 创建奔驰具体产品角色* <p>Title: BenzCar</p> * @author Liyan * @date 2017年4月26日 下午2:01:31*/ public class BenzCar implements Car {@Overridepublic void creatCar() {System.out.println("奔驰车实体已经创建好了!");} }
③创建宝马具体产品角色
package com.liyan.factory; /*** 创建宝马具体产品角色* <p>Title: BmwCar</p> * @author Liyan * @date 2017年4月26日 下午1:59:31*/ public class BmwCar implements Car {@Overridepublic void creatCar() {System.out.println("宝马车实体已经创建好了!");} }
④创建奔驰玛莎拉蒂具体产品角色
package com.liyan.factory; /*** 创建玛莎拉蒂具体产品角色* <p>Title: MaseratiCar</p> * @author Liyan * @date 2017年4月26日 下午2:02:44*/ public class MaseratiCar implements Car {@Overridepublic void creatCar() {System.out.println("玛莎拉蒂车实体已经创建好了!");} }
⑤创建工厂类角色
package com.liyan.factory; /*** 创建工厂类角色* <p>Title: CarFactory</p> * @author Liyan * @date 2017年4月26日 下午2:09:36*/ public class CarFactory {/*** <p>Title: creatCar</p> * @author Liyan * @date 2017年4月26日 下午2:09:49 * @param carName 车的名字* @return Car 返回抽象类。想想依赖倒转原则:依赖于抽象而不依赖于具体*/public static Car creatCar(String carName) {if (carName.equalsIgnoreCase("Benz")) {return new BenzCar();}if (carName.equalsIgnoreCase("Bmw")) {return new BmwCar();}if (carName.equalsIgnoreCase("Maserati")) {return new MaseratiCar();} return null;} }
⑥某思聪登场
package com.liyan.factory; /*** 某思聪* <p>Title: SiCong</p> * @author Liyan * @date 2017年4月26日 下午2:12:48*/public class SiCong {public static void main(String[] args) {//某思聪发话要创建一辆宝马车Car car = CarFactory.creatCar("Bmw");//车开始创建,输出是具体的宝马车car.creatCar();} }
关系图如下:
以上便是简单工厂的例子,有没有发现很简单呢。但是,你是否发现它有些问题呢?比如,我再想创建一个产品3(创建一个劳斯莱斯车),这个时候就必须要修改CarFactory工厂角色类,那样的话是不是就不符合开闭原则(对扩展开放,对修改关闭)了呢?于是,我就有了工厂方法模式。
2.工厂方法模式
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这
样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。
【Java代码】
①创建一个抽象产品角色及具体产品角色(Car、BenzCar、BmwCar、MaseratiCar)同上。
②创建工厂角色
package com.liyan.factorymethod; /*** 2号工厂,演示工厂方法模式* <p>Title: CarFactory2</p> * @author Liyan * @date 2017年4月26日 下午3:24:31*/ public interface CarFactory {public Car creatCar(); }
③创建奔驰分厂角色
package com.liyan.factorymethod; /*** 创建奔驰的分厂* <p>Title: BenzCarFactory</p> * @author Liyan * @date 2017年4月26日 下午3:37:58*/ public class BenzCarFactory implements CarFactory {@Overridepublic Car creatCar() {return new BenzCar();} }
④创建宝马分厂角色
package com.liyan.factorymethod; /*** 创建宝马的分厂* <p>Title: BenzCarFactory</p> * @author Liyan * @date 2017年4月26日 下午3:38:02*/ public class BmwCarFactory implements CarFactory {@Overridepublic Car creatCar() {return new BmwCar();} }
⑤创建玛莎拉蒂的分厂角色
package com.liyan.factorymethod; /*** 创建玛莎拉蒂的分厂* <p>Title: MaseratiCarFactory</p> * @author Liyan * @date 2017年4月26日 下午3:40:51*/ public class MaseratiCarFactory implements CarFactory {@Overridepublic Car creatCar() {return new MaseratiCar();} }
⑥某思聪登场
package com.liyan.factorymethod; /*** 某思聪* <p>Title: SiCong</p> * @author Liyan * @date 2017年4月26日 下午2:12:48*/ public class SiCong {public static void main(String[] args) {//把创建对象的压力分散到具体的分厂CarFactory carFactory = new MaseratiCarFactory();//分厂创建玛莎拉蒂Car car = carFactory.creatCar();car.creatCar();} }
关系图如下:
这就是工厂方法模式。为每一个产品,单独创建一个分厂。这样就符合了开闭原则。但是,依然存在弊端:可以看出工厂方法的加入,使得对象的数量成倍增长,当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。
所以,它的适用场景是:
1) 当客户程序不需要知道要使用对象的创建过程。
2) 客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个具体的对象。
细心的人可能发现,其实工厂模式并没有真正的解决代码的改动问题。比如简单工厂,新增产品要修改工厂类;工厂方法模式,新增产品要创建新工厂。面对这样的瓶颈问题,难道真的没办法解决了吗?
答案肯定是否定的。仅做一个小提示,关键字:Spring、配置文件、反射。
3.抽象工厂模式
抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。
(解释一下什么叫产品族?简单理解,一系列同类型产品的集合。比如奔驰,下面又可分为:奔驰汽车、奔驰跑车、奔驰商务车、奔驰SUV等,这些分支及以下的产品,都可以统称为产品族)
【Java代码】
①创建车身抽象产品角色及具体产品角色(Car、BenzCar、BmwCar、MaseratiCar)同上。
②创建车类型抽象产品角色及具体产品角色
package com.liyan.abstractfactory; /*** 车的类型抽象产品类型* <p>Title: CarType</p> * @author Liyan * @date 2017年4月26日 下午4:41:05*/ public interface CarType {/*** 创建车的类型* <p>Title: createCarType</p> * @author Liyan * @date 2017年4月26日 下午4:42:42 * void*/public void createCarType(); }
商务类型产品角色
package com.liyan.abstractfactory; /*** 商务类型* <p>Title: BusinessCarType</p> * @author Liyan * @date 2017年4月26日 下午4:43:54*/ public class BusinessCarType implements CarType{@Overridepublic void createCarType() {System.out.println("我是商务类型!");} }
SUV类型产品角色
package com.liyan.abstractfactory; /*** SUV类型* <p>Title: BusinessCarType</p> * @author Liyan * @date 2017年4月26日 下午4:43:54*/ public class SuvCarType implements CarType{@Overridepublic void createCarType() {System.out.println("我是SUV类型!");} }
跑车类型产品角色
package com.liyan.abstractfactory; /*** 跑车类型* <p>Title: BusinessCarType</p> * @author Liyan * @date 2017年4月26日 下午4:43:54*/ public class RunCarType implements CarType{@Overridepublic void createCarType() {System.out.println("我是跑车类型!");} }
③为车和车类型创建抽象类来获取工厂(此时为抽象类,不再是接口!)
package com.liyan.abstractfactory; /*** 3号工厂,演示抽象工厂模式(抽象类,不再是接口!)* <p>Title: CarFactory2</p> * @author Liyan * @date 2017年4月26日 下午3:24:31*/ public abstract class Factory {/*** 创建车主体* <p>Title: creatCar</p> * @author Liyan * @date 2017年4月26日 下午4:47:51 * @return Car*/abstract Car creatCar(String carName);/*** 创建车的类型* <p>Title: creatCarType</p> * @author Liyan * @date 2017年4月26日 下午4:48:01 * @return CarType*/abstract CarType creatCarType(String carType); }
④创建车体子类工厂
package com.liyan.abstractfactory; import com.liyan.abstractfactory.BenzCar; import com.liyan.abstractfactory.BmwCar; import com.liyan.abstractfactory.MaseratiCar; /*** 创建车体子类工厂* <p>Title: CarFactory</p> * @author Liyan * @date 2017年4月26日 下午4:56:14*/ public class CarFactory extends Factory {@OverrideCar creatCar(String carName) {if (carName.equalsIgnoreCase("Benz")) {return new BenzCar();}if (carName.equalsIgnoreCase("Bmw")) {return new BmwCar();}if (carName.equalsIgnoreCase("Maserati")) {return new MaseratiCar();}return null;}@OverrideCarType creatCarType(String carType) {return null;} }
⑤创建车类型子类工厂
package com.liyan.abstractfactory; /*** 创建车类型子类工厂* <p>Title: CarTypeFactory</p> * @author Liyan * @date 2017年4月26日 下午5:04:57*/ public class CarTypeFactory extends Factory {@OverrideCar creatCar(String carName) {return null;}@OverrideCarType creatCarType(String carType) {if (carType.equalsIgnoreCase("Business")) {return new BusinessCarType();}if (carType.equalsIgnoreCase("Suv")) {return new SuvCarType();}if (carType.equalsIgnoreCase("Run")) {return new RunCarType();}return null;} }
⑥创建一个工厂创造器/生成器类,通过传递车品牌或车类型信息来获取工厂。
package com.liyan.abstractfactory; /*** 工厂创造器/生成器类* <p>Title: FactoryProducer</p> * @author Liyan * @date 2017年4月26日 下午5:08:11*/ public class FactoryProducer {public static Factory getFactory(String key) {if (key.equalsIgnoreCase("Car")) {return new CarFactory();}if (key.equalsIgnoreCase("CarType")) {return new CarTypeFactory();}return null;} }
⑦我们的主角思聪登场
package com.liyan.abstractfactory; /*** 某思聪* <p>Title: SiCong</p> * @author Liyan * @date 2017年4月26日 下午2:12:48*/ public class SiCong {public static void main(String[] args) {//某思聪此时想要一辆宝马款的商务车//1.通过工厂触发器,获取创建车体的工厂Factory carFactory = FactoryProducer.getFactory("Car");Car car = carFactory.creatCar("Bmw");car.creatCar();//2.通过工厂触发器,获取创建车类型的工厂Factory typeFactory = FactoryProducer.getFactory("CarType");CarType carType = typeFactory.creatCarType("Business");carType.createCarType(); } }
关系图如下:
总结(简单工厂,工厂方法,抽象工厂三者的异同):
(1)相同点:
都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,优化了系统的架构,并且增强了系统的扩展性。
(2)不同点:
①简单工厂模式:一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例。不满足开闭原则(不修改代码的话,是无法扩展的)。
②工厂方法模式:针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。在同一等级结构中,支持增加任意产品。满足开闭原则。
③抽象工厂模式:应对产品族概念而生,增加新的产品线很容易,但是无法增加新的产品。
【秒懂设计模式】总述及工厂模式相关推荐
- 设计模式(五)--工厂模式汇总
LZ想把简单工厂模式.工厂方法模式和抽象工厂模式整理到一篇博文当中,由浅入深,应该能方便理解和记忆,话不多说,进入正题. 一.简单工厂模式 定义:从设计模式的类型上来说,简单工厂模式是属于创建型模式, ...
- 设计模式 笔记4 | 简单工厂模式 在源码中的应用 | Calendar 日历 | 源码浅析 | 使用总结 | 建造者模式
文章目录 一.Calendar 日历类 1.1 内部属性 1.2 设置时间属性值 1.3 获取时间属性 1.4 使用 Calander 计算时间 二.Calender 类中的设计模式 2.1 简单工厂 ...
- 设计模式C#描述——抽象工厂模式
设计模式C#描述--抽象工厂模式 阅读此文应先阅读简单工厂模式与工厂方法模式 抽象工厂模式是对象的创建模式,它是工厂方法模式的进一步推广. 假设一个子系统需要一些产品对象,而这些产品又属于一个以上的产 ...
- Java设计模式(1)工厂模式(Factory模式)
工厂模式定义:提供创建对象的接口. 为何使用工厂模式 工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见. 为什么工厂模式是如此常用?因 ...
- 设计模式系列——三个工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)...
转自:http://www.cnblogs.com/stonehat/archive/2012/04/16/2451891.html 设计模式系列--三个工厂模式(简单工厂模式,工厂方法模式,抽象工厂 ...
- 23种设计模式 -----Day01:简单工厂模式
目录 前言 1.设计模式(Design pattern)定义 2.为什么要使用设计模式(使用设计模式的意义) 3.设计原则 a.单一职责原则 b.开放封闭原则 c.里氏代换原则 d.迪米特法则 e.依 ...
- 一口气讲完设计模式(单例模式、工厂模式、原型模式、建造者模式、适配器、桥梁模式)
设计模式 使用设计模式,可以让我们的代码具有更好的可读性.可扩展性.可读性.重用性.符合高内聚低耦合的特点.作为程序员,是我们经常听到的概念,也是我们程序员必须深入学习,了解的知识. 设计模式种类 该 ...
- 设计模式之创建型——工厂模式(3种)
→23种设计模式大纲 三种工厂模式 →23种设计模式大纲 定义 分类 1)简单工厂 UML类图 2)工厂方法 UML类图 3)抽象工厂 UML类图 总结 定义 将创建对象这一复杂的过程交由工厂控制,通 ...
- 【23种设计模式专题】二 工厂模式
程序猿学社的GitHub,欢迎Star github技术专题 本文已记录到github 文章目录 前言 小故事 传统方式 简单工厂(第一种) 工厂方法模式(第二种) 抽象工厂模式(第三种) 使用工厂方 ...
最新文章
- python构造方法与java区别_一张图秒懂Java和Python的区别,你知道吗?
- PHP性能调优,PHP慢日志---PHP脚本执行效率性能检测之WebGrind的使用
- 无休止加班的真正原因!你们公司是这样吗?
- C++读写EXCEL文件方式比较 .
- mysql json 中日期_mysql 转换json 时间问题
- 在华为笔记本 MateBook 13 (MX250)上配置yolo-v3_tensorflow CUDA 所遇到的一些坑(cuda无法识别显卡)
- 深度干货 | 多维分析中的 UV 与 PV
- Boost:组合异步操作的简单示例
- iphone查看删除的短信_苹果删除的短信
- react 组件传值
- 2021巨量引擎连锁经营行业洞察报告
- UVA 10047 - The Monocycle BFS
- java算法题走楼梯,程序员必学算法「动态规划」:爬楼梯(完全背包解法)
- CPP_template
- LNMP下wordpress无法切换主题,只显示当前主题解决方法
- Unity 录制简单的动画
- Markdown编辑器-MarkdownPad下载与安装(win10)
- vue 中 keep-alive,activated,deactivated
- 人,羊,狼,菜过河问题的计算机编程实现的matlab程序,人狼羊菜渡河问题(含Matlab程序)...
- linux 烧写stm32 swd,STM32F103使用SWD烧写错误提示的问题
热门文章
- Linux查看文件cat、tail、vim
- python爬取豆瓣短评_爬虫-爬取豆瓣短评
- flink-cdc 基础教程 完结 附报错解决(二)
- 2023.3.8国内免费100个HTTP代理IP
- css文字内容省略[...]
- 一位初级进阶中级 JavaScript 工作者的自我修养(一)
- JAVASE 面向对象
- Coursera | Andrew Ng (02-week-3-3.3)—超参数训练的实践:Pandas VS Caviar
- 细说贝叶斯滤波:Bayes filters
- 《投资中最简单的事》读后感