大家熟知的23种设计模式,可以分为创建型模式、结构型模式和行为型模式三大类。其中,创建型模式是对类的实例化过程进行抽象,从而将对象的创建和使用分离开。主要有简单工厂模式、工厂方法模式和抽象工厂模式3种。

工厂模式核心:

工厂模式的核心思想就是把创建对象和使用对象解藕,由工厂负责对象的创建,而用户只能通过接口来使用对象,这样就可以灵活应对变化的业务需求,方便代码管理、避免代码重复。

假设我们在工作中需要将产品 a 升级为产品 A ,如果创建对象的工作是由用户来做,也就是用户通过 new a() 的形式创建对象,那么为了应对新的产品升级需求,我们还需要找到所有相关代码并将它们改为 new A(),在庞大工程下就是一项极为繁琐的工作;而通过应用工厂模式,将所有对象创建工作交由工厂管理时,我们就可以直接在工厂中将 return new a() 改为 return new A() ,用户仍然可以调用 factory.createProduct()方法而无须更改原本的代码。这样工厂可以通过复用来减少重复代码量,并且用户无需关注创建对象的逻辑。

工厂模式在 Java 程序员的工作中可以说是无处不在:我们最常用的 Spring 就是一个Bean 工厂,IOC 通过BeanFactory 对 Bean 进行管理(可参考上面这张类图);我们使用的日志框架 slf4j 使用了工厂方法模式;JDK 的 Calendar 使用了简单工厂模式

一、简单工厂模式

简单工厂模式是最简单的一种工厂模式,它定义了一个负责生产对象的工厂类,使用者可以根据不同参数来创建并返回不同子类,这些子类都共用一个接口(即父类)

简单工厂模式包含三种类,分别是抽象产品类、具体产品类、工厂类,下面分别对各类及它们之间的关系作进一步说明。

角色 关系 作用
抽象产品 Product  具体产品的父类 描述产品的公共接口
具体产品 ConcreteProduct 抽象产品的子类;工厂创建的目标类 描述生产的具体产品
工厂 Factory 外界调用 根据传入的不同参数来创建不同具体产品类的实例

使用步骤:

  1. 创建抽象产品类,并为具体产品定义好一个接口;

  2. 创建具体产品类,其通过接口来继承抽象产品类,同时也要定义计划生产的每一个具体产品;

  3. 创建工厂类,其创建的静态方法可以对传入的不同参数做出响应;

  4. 外界使用者就能调用工厂类的静态方法了,通过传入不同参数来创建不同具体产品类的实例。


//step1:创建抽象产品类,定义具体产品的公共接口
public abstract class Shirt{public abstract void Show();
}//step2:创建具体产品类(继承抽象产品类),定义生产的具体产品
//具体产品类A,女款衬衫
public class WomenShirt extends Shirt{@Overridepublic void Show(){System.out.println("展示女款衬衫");}
}
//具体产品类B,男款
public class MenShirt extends Shirt{@Overridepublic void Show(){System.out.println("展示男款衬衫");}
}//step3:创建工厂类,通过静态方法处理不同传入参数,从而创建不同具体产品类的实例
public class Factory{public static Shirt Exhibit(String ShirtName){switch(ShirtName){case "女款衬衫":return new WomenShirt();case "男款衬衫":return new MenShirt();default:return null;}}
}//step4:外界调用工厂类的静态方法,传入不同参数创建不同具体产品类的实例
public class SimpleFactoryPattern{public static void main(String[] args){Factory exhibitFactory = new Factory();//用户搜索女款衬衫try{//调用工厂类的静态方法,传入参数并创建实例exhibitFactory.Exhibit("女款衬衫").Show();}catch(NullPointerException e){System.out.println("没有找到商品");}//用户搜索男款裤子try{exhibitFactory.Exhibit("男款裤子").Show();}catch(NullPointerException e){System.out.println("没有找到商品");}//用户搜索男款衬衫try{exhibitFactory.Exhibit("男款衬衫").Show();}catch(NullPointerException e){System.out.println("没有找到商品");}}
}

优点

  1. 将对象的使用和创建过程分离开,实现解藕。客户端不需要关注对象是谁创建的、怎么创建的,只要通过工厂中的静态方法就可以直接获取其需要的对象。

  2. 将初始化实例的工作放到工厂里执行,代码易维护, 更符合面向对象的原则,做到面向接口编程,而不是面向实现编程。

缺点

  1. 工厂类中需要选择创建具体某个对象,所以一旦添加新产品则必须要对工厂中的选择逻辑进行修改,导致工厂逻辑过于复杂,违背开闭原则。

  2. 工厂类集合了所有实例(具体产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响。

  3. 静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。

  • 适用场景

  1. 具体产品类较少时,使用简单工厂模式可以实现生产者与消费者的分离,而且也不会在工厂类中设定太复杂的判断逻辑。

  2. 使用者只知道传入工厂类的参数,不关心如何创建对象的逻辑时。

二、工厂方法模式

工厂方法模式包含四种类,分别是抽象产品类、具体产品类、抽象工厂类、具体工厂类,下面分别对各类以及它们之间的关系作进一步说明。

角色

关系

作用

抽象产品 Product

具体产品的父类

描述产品的公共接口

具体产品 ConcreteProduct

抽象产品的子类;工厂创建的目标类

描述生产的具体产品

抽象工厂 Factory

具体工厂的父类

描述具体工厂的公共接口

具体工厂 ConcreteFactory

抽象工厂的子类,外界调用

描述具体工厂;实现Factory接口,创建具体产品实例

使用步骤概括如下:

  1. 创建抽象工厂类,定义具体工厂的公共接口;

  2. 创建抽象产品类,定义具体产品的公共接口;

  3. 创建具体产品类(继承抽象产品类),定义生产的具体产品;

  4. 创建具体工厂类(继承抽象工厂类),定义创建相应具体产品实例的方法;

  5. 外界调用具体工厂类的方法,创建不同具体产品类的实例。

//step1:创建抽象工厂类,定义具体工厂的公共接口
public abstract class Factory{public abstract Shirt Exhibit();
}//step2:创建抽象产品类,定义具体产品的公共接口
public abstract class Shirt{public abstract void Show();
}//step3:创建具体产品类(继承抽象产品类),定义生产的具体产品
//具体产品类A,女款衬衫
public class WomenShirt extends Shirt{@Overridepublic void Show(){System.out.println("展示女款衬衫");}
}
//具体产品类B,男款衬衫
public class MenShirt extends Shirt{@Overridepublic void Show(){System.out.println("展示男款衬衫");}
}//step4:创建具体工厂类,定义创建具体产品实例的方法
//具体工厂类A,展示女款衬衫类商品
public class WomenShirtFactory extends Factory{@Overridepublic Shirt Exhibit(){return new WomenShirt();}
}
//具体工厂类B,展示男款衬衫类商品
public class MenShirtFactory extends Factory{@Overridepublic Shirt Exhibit(){return new MenShirt();}
}//step5:外界调用具体工厂类的方法,创建不同具体产品类的实例
public class FactoryPattern{public static void main(String[] args){//用户在店铺搜索女款衬衫Factory exhibitWomenShirtFactory = new WomenShirtFactory();exhibitWomenShirtFactory.Exhibit().Show();//用户在店铺搜索男款衬衫Factory exhibitMenShirtFactory = new MenShirtFactory();exhibitMenShirtFactory.Exhibit().Show();       }
}

优点

  1. 符合开闭原则。新增一种产品时,只需要增加相应的具体产品类和工厂子类即可,可方便的生产或切换产品,而无须像简单工厂模式那样修改工厂类的判断逻辑,具有更高的扩展性 。

  2. 符合单一职责原则。每个具体工厂类只负责创建对应的具体产品,而简单工厂中的工厂类存在复杂的switch逻辑判断。

  3. 相比于简单工厂模式,使用的不是静态方法,可形成基于继承的等级结构

缺点

  1. 一个具体工厂只能创建一种具体产品。添加新产品时,除增加新产品类外,还要提供与之对应的具体工厂类,类的个数成对增加,在一定程度上增加了系统复杂度;同时有更多的类需要编译和运行,给系统带来额外开销。

  2. 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

  3. 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类。

  4. 难以对父类接口进行修改,因为一旦修改接口,就必须要对众多的帮忙子类进行修改。

  • 适用场景

  1. 一个类不确定它所必须创建的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可。

  2. 你期望获得较高的扩展性。

  3. 一个类希望由它的子类来指定它所创建的对象。在工厂方法模式中,对于抽象工厂类只需提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏替换原则,在程序运行时,子类对象将覆盖父类对象,从而使系统更容易扩展。

  4. 当类将创建对象的职责委托给多个工厂子类的中的某一个,且用户知道将要使用哪一个工厂子类。

三、 抽象工厂模式

抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。抽象工厂模式与工厂方法模式最大的区别:抽象工厂中每个具体工厂可以创建多类具体产品;而工厂方法每个具体工厂只能创建一类具体产品

工厂方法模式包含五种类,分别是抽象产品族类、抽象产品类、具体产品类、抽象工厂类、具体工厂类

角色

关系

作用

抽象产品族 AbstractProduct

抽象产品的父类

描述抽象产品的公告接口

抽象产品 Product

具体产品的父类

描述具体产品的公共接口

具体产品 ConcreteProduct

抽象产品的子类;工厂创建的目标类

描述生产的具体产品

抽象工厂 Factory

具体工厂的父类

描述具体工厂的公共接口

具体工厂 ConcreteFactory

抽象工厂的子类,外界调用

描述具体工厂;实现Factory接口,创建具体产品实例

使用步骤概括如下:

  1. 创建抽象工厂类,定义具体工厂的公共接口;

  2. 创建抽象产品族类,定义抽象产品的公共接口;

  3. 创建抽象产品类(继承抽象产品族类),定义具体产品的公共接口;

  4. 创建具体产品类(继承抽象产品类),定义生产的具体产品;

  5. 创建具体工厂类(继承抽象工厂类),定义创建相应具体产品实例的方法;

  6. 外界调用具体工厂类的方法,创建不同具体产品类的实例。

//step1:创建抽象工厂类,定义具体工厂的公共接口
public abstract class Factory{public abstract Clothing ExhibitShirt();public abstract Clothing ExhibitTrousers();
}//step2:创建抽象产品族类,定义抽象产品的公共接口
public abstract class Clothing{public abstract void Show();
}//step3:创建抽象产品类,定义具体产品的公共接口
//女装抽象类
public abstract class Shirt extends Clothing{@Overridepublic abstract void Show();
}
//男装抽象类
public abstract class Trousers extends Clothing{@Overridepublic abstract void Show();
}//step4:创建具体产品类(继承抽象产品类),定义生产的具体产品
//衬衫产品类A,淘宝衬衫
public class TBShirt extends Shirt{@Overridepublic void Show(){System.out.println("展示淘宝店铺衬衫");}
//衬衫产品类B,淘特衬衫
public class TTShirt extends Shirt{@Overridepublic void Show(){System.out.println("展示淘特店铺衬衫");}
}
//裤子产品类A,淘宝裤子
public class TBTrousers extends Trousers{@Overridepublic void Show(){System.out.println("展示淘宝店铺裤子");}
}
//裤子产品类B,淘特裤子
public class TTTrousers extends Trousers{@Overridepublic void Show(){System.out.println("展示陶特店铺裤子");}
}//step5:创建具体工厂类,定义创建具体产品实例的方法
//淘宝工厂类A,展示衬衫+裤子
public class TBFactory extends Factory{@Overridepublic Clothing ExhibitShirt(){return new TBShirt();}@Overridepublic Clothing ExhibitTrousers(){return new TBTrousers();}
}
//淘特工厂类B,展示裤子+衬衫
public class TTFactory extends Factory{@Oversidepublic Clothing ExhibitShirt(){return new TTShirt();}@Oversidepublic Clothing ExhibitTrousers(){return new TTTrousers();}
}//step6:外界实例化具体工厂类,调用工厂类中创建不同目标产品的方法,创建不同具体产品类的实例
public class AbstractFactoryPattern{public static void main(String[] args){TBFactory exhibitTBFactory = new TBFactory();TTFactory exhibitTTFactory = new TTFactory();//淘宝用户搜索衬衫exhibitTBFactory.ExhibitShirt().Show();//淘宝用户搜索衬衫exhibitTBFactory.ExhibitTrousers().Show();//淘特用户搜索衬衫exhibitTTFactory.ExhibitShirt().Show();//淘特用户搜索衬衫exhibitTTFactory.ExhibitTrousers().Show();     }
}

优点

  1. 降低耦合度。抽象工厂模式将具体产品的创建延迟到具体工厂类中,这样将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而降低系统耦合度,有利于后期的维护和扩展。

  2. 符合开闭原则。新增一种产品类时,只需增加相应的具体产品类和工厂子类即可,简单工厂模式需要修改工厂类的判断逻辑。

  3. 符合单一职责原则。每个具体工厂类只负责创建对应的产品,简单工厂模式中的工厂类需要进行复杂的 switch 逻辑判断。

  4. 不使用静态工厂方法,可以形成基于继承的等级结构。

  5. 便于添加更换产品族。因为具体产品都是由具体工厂创建的,所以在更换产品族的时候只要简单修改具体工厂即可。

  6. 具体产品的创建过程和客户端隔离。客户端通过操作抽象产品接口实现操作具体产品实例,具体产品的类名不会出现在客户端中。

缺点

  1. 难以支持新种类产品的变化。这是因为抽象工厂接口中已经确定了可被创建的产品集合,如果需要添加新产品,此时就必须去添加抽象产品接口,还要在抽象工厂接口中添加新方法,并在所有具体工厂中实现该新方法。这样就会改变抽象工厂类以及所有具体工厂子类的改变,违背开闭原则。

  2. 类图有点复杂,可读性没有工厂方法模式高。

  • 适用场景

  1. 系统不要求依赖产品类实例如何被创建、组合和表达,这点也是所有工厂模式应用的前提。

  2. 系统要求提供一个产品类的库,所有产品以同样的接口出现,客户端不需要依赖具体实现。

  3. 系统中有多个产品族,但每次只使用其中某一族产品。(切换产品族只需修改具体工厂对象即可)


简单工厂模式:让一个工厂类负责创建所有对象;但没有考虑后期扩展和维护,修改违背开闭原则,静态方法不能被继承。

工厂方法模式:主要思想是继承,修改符合开闭原则;但每个工厂只能创建一种类型的产品。

抽象工厂模式:主要思想是组合,本质是产品族,实际包含了很多工厂方法,修改符合开闭原则;但只适用于增加同类工厂这种横向扩展需求,不适合新增功能方法这种纵向扩展。



其实这三种工厂模式在形式和特点上都非常相似,甚至存在一定的内在联系,而且最终目的都是解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为它们之间也是可以灵活转变的。比如你原本使用的是工厂方法模式,加入一个新方法后就可能会让具体产品类构成不同等级结构中的产品族,代码结构就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个或多个具体产品类时,使原有产品族只剩下一个产品后,代码结构也就转变成了工厂方法模式。

设计模式—1-工厂模式相关推荐

  1. Java设计模式(工厂模式>抽象工厂模式和原型模式)

    Java设计模式Ⅱ 1.工厂模式 1.1 简单工厂模式 1.2 工厂方法模式 2.抽象工厂模式 3.总结 4.原型模式 4.1 原型模式 4.2 浅拷贝 4.3 深拷贝 5.建造者模式 1.工厂模式 ...

  2. JavaScript设计模式--简单工厂模式例子---XHR工厂

    JavaScript设计模式--简单工厂模式例子---XHR工厂 第一步,Ajax操作接口(目的是起一个接口检测作用) (1)引入接口文件 //定义一个静态方法来实现接口与实现类的直接检验 //静态方 ...

  3. 三角形圆形创建与擦除java_设计模式---------------简单工厂模式

    设计模式---------------简单工厂模式 一.题目(Question) 使用简单工厂模式设计一个可以创建不同几何形状(如圆形.方形和三角形等)的绘图工具,每个几何图形都要有绘制draw()和 ...

  4. 策略模式和工厂模式的区别_设计模式之工厂模式-工厂方法模式

    设计模式之工厂模式-工厂方法模式 大家好,欢迎来到污污弹公司,今天司小司又接到了一个新活-披萨项目. 来源:凯哥Java(kaigejava) 需求: 披萨项目: 要方便披萨品种的扩展.要便于维护.要 ...

  5. Java 设计模式之工厂模式(二)

    原文地址:Java 设计模式之工厂模式(二) 博客地址:http://www.extlight.com 一.背景 本篇内容是 Java 设计模式创建型模式的第二篇.上一篇主题为 <Java 设计 ...

  6. 设计模式之工厂模式(三)

    上一次我们已经通过代码,简单的认识了工厂方法模式,具体的思路请移步到设计模式之工厂模式(二),进行查看.这次,让我们通过设计模式的思想,来好好认识下工厂方法模式. 创建者和产品 所有工厂模式都用来封装 ...

  7. php工厂模式和单例模式,php 设计模式之工厂模式、单例模式、注册树模式

    php 设计模式之工厂模式.单例模式.注册树模式 在软件工程中,创建型设计模式承担着对象创建的职责,尝试创建适合程序上下文的对象,对象创建设计模式的产生是由于软件工程设计的问题,具体说是向设计中增加复 ...

  8. 教你如何一篇博客读懂设计模式之—--工厂模式

    一篇博客读懂设计模式之-工厂模式 工厂模式在我们日常开发的时候经常用到,相信大家都有了一定的了解,工厂模式是一种创建对象的设计模式,它提供一种创建对象的最佳方式. 主要过程是: 定义一个创建对象的接口 ...

  9. 一篇博客读懂设计模式之---工厂模式

    设计模式之-工厂模式 工厂模式: 创建过程: 创建Shape接口 public interface Shape {void draw(); } 创建实现类: public class Circle i ...

  10. java 工厂模式详解_Java设计模式之工厂模式详解

    简单工厂其实并不是设计模式,只是一种编程习惯. 首先我们创建父类Cup,所有杯子类的父类.再创建它的子类BigCup和SmallCup类. public abstract class Cup { pu ...

最新文章

  1. DFS、DTFT、DFT、 FFT的定义和区别
  2. linux内核线性地址等于物理地址,Linux 从虚拟地址到物理地址
  3. ×××:关于促进云计算创新发展 培育信息产业新业态的意见
  4. MUI 里js动态添加数字输入框后,增加、减少按钮无效
  5. flask 必知必会
  6. 计算机程序的建立命令,数控车床编程指令 编程由一系列的指令组成
  7. Android与Asp.Net Web服务器的文件上传下载BUG汇总[更新]
  8. SGPN: Similarity Group Proposal Network for 3D Point Cloud Instance Segmentation
  9. Android xml文件的序列化
  10. linux驱动基础开发1——linux 设备驱动基本概念-转
  11. 计算机是怎样跑起来的pdf_程序是怎样跑起来的 -- 通过汇编语言了解程序的实际构成(中篇)...
  12. Java 调用执行其他语言的程序
  13. ColorBlinder(我是色盲)
  14. kibana如何使用linux命令,Kibana 用户指南(安装Kibana)
  15. Hibernate二级缓存以及ehcache的搭建配置
  16. 2021数据结构学习笔记(严蔚敏版)
  17. matlab画圆的命令_matlab画圆命令资料
  18. Greenplum单机版部署
  19. 北邮计算机考研科目2022,2022考研:北京邮电大学计算机专业考研经验复习指导...
  20. 阿里内核月报2014年7月-8月

热门文章

  1. 将一个数分解为质因数的乘积
  2. VirtualKD加速windbg双机调试速度
  3. python花式索引_ndarray花式索引
  4. Cisco UC-功能-01-电话-拔出拔入-Cisco IP Phone
  5. 红眼睛微型红外成像仪
  6. esp8266 nodemcu 自制mp3
  7. python入门环境搭建
  8. IIS 错误:定义了重复的“system.web.extensions/scripting/scriptResourceHandler”节
  9. 青风和大家一起学Stellaris系列ARM——五.看门狗的使用
  10. idea中actiBPM插件生成png文件 ,右键xml文件没有Diagrams