前言

创建型模式中,常用的有工厂方法模式和抽象工厂模式,平时实践还包括简单工厂模式,虽然简单工厂模式不在23种设计模式中。
为了区分以上几种设计模式的差别,通过以下几个例子介绍这几种模式的使用场景以及优缺点。当然,由于本人接触设计模式时间还不长,难免有疏漏之处,欢迎各位提出意见。

不采用设计模式的情况

考虑如今有一个产品,比如椅子,该椅子可以有多种风格,比如中式的,或者美式的。如果我们不想通过设计模式,想要什么类型的椅子,就可以直接实例化某个实体类获得。

“ChineseChair.java”——实体类

public class ChineseChair {public void sit(){System.out.println("这把椅子很具有文化气息");}
}

“Client.java”——用户

public class Client {public static void main(String[] args) {ChineseChair chair = new ChineseChair();chair.sit();}
}

貌似当用户使用这种最基本的通过new关键字实例化一个对象的方式,并没有什么问题。但考虑如果我们要实例化的对象改为USAChair,那么所有之前使用ChineseChair的地方,都要进行修改,这不是一个小工程。
同样的,当前的ChineseChair类实例化的使用,采用的无参构造方法,如果是有参构造方法,那么就不可以避免地要传入参数。但作为用户来说,更希望用更加封装的方式获取某个实例对象,而不用考虑它的构造细节。
另外,在一个大型程序中,我们更希望对象的生命周期被集中统一的管理,当前情况下,每次要调用ChineseChair,都要实例化一次,因此效率不高。
针对这些问题,我们可以采用简单工厂模式。

简单工厂模式

考虑到如果有多个属于同一类别的产品,用户哪怕需要切换产品,但产品的使用方式总是不变的(比如对于椅子这一类产品,虽然可以有多种风格,但总归都是用来sit的),因此可以用同一的方式返回用户需要的产品。
简单工厂模式的核心包括以下:一个所有产品必须实现的接口(该接口规定了产品的通用对外功能),一个用于生产产品的工厂类。一般为了方便,工厂类中产生产品的方法,通常采用静态方法的方式,代码如下。

“Chair.java”——所有椅子类产品都要遵循的接口

public interface Chair {public void sit();
}

“ChairType.java”——枚举类,标识椅子类型

public enum ChairType {CHINESECHAIRTYPE,USACHAIRTYPE
}

“ChineseChair.java”——中式风格椅子,实现Chair接口

public class ChineseChair implements  Chair{public void sit(){System.out.println("这把中国椅子充满了文化气息");}
}

“USAChair.java”——美式风格的椅子,实现Chair接口

public class USAChair implements Chair{public void sit(){System.out.println("这把美国椅子很具有后现代风格");}
}

“ChairFactory.java”——简单工厂类,生产Chair产品

public class ChairFactory {public static Chair createChair(ChairType type){switch (type){case CHINESECHAIRTYPE:return new ChineseChair();case USACHAIRTYPE:return new USAChair();default:return null;}}
}

“Client.java”——用户

public class Client {public static void main(String[] args) {Chair chair = ChairFactory.createChair(ChairType.CHINESECHAIRTYPE);chair.sit();}
}

好处:可以看到使用简单工厂模式,用户可以根据需要通过工厂类的静态方法,传入椅子类型的参数,从而获得对应种类的椅子。用户可以使用统一的方式获取想要的产品,而不用理会产品的产生细节。
缺陷:简单工厂模式并不是完美无缺,假如我们要新增一个JapaneseChair产品,那么无可避免的,需要针对工厂类的静态方法中,增加switch选项,这样不符合开闭原则。
重点:简单工厂模式描述了一个类,它拥有一个包含大量条件语句的构建方法,可以根据方法的参数来选择对何种产品进行初始化并将其返回。在大多数情况下,如果产品类型比较少,且比较固定,使用简单工厂模式就可以应付。

工厂方法模式

工厂方法模式的核心在于,将实例化产品的操作,延迟到工厂子类中执行。因此可以通过抽象类或者接口的方式,定义一个抽象工厂。同样的,也需要一个抽象的产品。之后具体的工厂类可以继承该抽象工厂,并且生产具体类型的产品。

“Chair.java”——抽象产品接口

public interface Chair {public void sit();
}

“ChineseChair.java”——具体产品1号

public class ChineseChair implements Chair{@Overridepublic void sit() {System.out.println("这把中式椅子很有古典文化气息");}
}

“USAChair.java”——具体产品2号

public class USAChair implements Chair{@Overridepublic void sit() {System.out.println("这把美国椅子很有后现代主义风格");}
}

“BaseFactory.java”——抽象工厂类

public abstract class BaseFactory {public abstract Chair createChair();//所有子类的共有方法public void doSth(){Chair chair = createChair();chair.sit();}
}

“ChineseFactory.java”——具体工厂类1

public class ChineseFactory extends BaseFactory{@Overridepublic Chair createChair() {return new ChineseChair();}
}

“USAFactory.java”——具体工厂类2

public class USAFactory extends BaseFactory{@Overridepublic Chair createChair() {return new  USAChair();}
}

“Client.java”——用户

public class Client {public static void main(String[] args) {BaseFactory factory = new ChineseFactory();factory.doSth();}
}

好处:之后如果新增产品类型,只需要新增工厂并且继承抽象工厂,重写抽象工厂中生产产品的方法就可以了,而抽象工厂本身不需要变动。

缺点:目前采用工厂方法模式,只能生产某个类型的产品,如果想要生产一系列不同类型的产品,就无能为力,因此需要使用抽象工厂模式。

抽象工厂模式

抽象工厂模式可以用于创建多种类型的产品,其主要原理是利用一个抽象的工厂接口,该接口中有多个抽象方法,每个方法可以生产某种类型的产品。因此如果要生产一系列产品,需要一个具体的工厂类,实现抽象类的所有抽象方法,每个方法返回一种类型的产品。

首先是产品:
“Table.java”——产品类型:桌子

public interface Table {public void put();
}

“Chair.java”——产品类性:椅子

public interface Chair {public void sit();
}

“ChineseChair.java”——具体椅子产品1

public class ChineseChair implements Chair{@Overridepublic void sit() {System.out.println("这把中式椅子很有古典气息");}
}

“USAChair.java”——具体椅子产品2

public class USAChair implements Chair{@Overridepublic void sit() {System.out.println("这把美式椅子彰显了后现代主义风格");}
}

“ChineseTable.java”——具体桌子产品1

public class ChineseTable implements Table{@Overridepublic void put() {System.out.println("这张中式桌子放了一碗常州鳝丝面");}
}

“USATable.java”——具体桌子产品2

public class USATable implements Table{@Overridepublic void put() {System.out.println("这张美式桌子上放了一个汉堡");}
}

“BaseFactory.java”——抽象工厂接口

public interface BaseFactory {public Chair createChair();public Table createTable();
}

接下来为工厂:

“BaseFactory.java”——抽象工厂接口

public interface BaseFactory {public Chair createChair();public Table createTable();
}

“ChineseFactory.java”——具体工厂1

public class ChineseFactory implements BaseFactory{@Overridepublic Chair createChair() {return new ChineseChair();}@Overridepublic Table createTable() {return new ChineseTable();}
}

“USAFactory.java”——具体工厂2

public class USAFactory implements BaseFactory{@Overridepublic Chair createChair() {return new USAChair();}@Overridepublic Table createTable() {return new USATable();}
}

最后是用户:
“Client.java”

public class Client {public static void main(String[] args) {BaseFactory factory = new ChineseFactory();Chair chair  = factory.createChair();Table table = factory.createTable();chair.sit();table.put();}
}

总结:

1.工厂方法和抽象工厂的区别与联系

(1)工厂方法模式的核心是创建产品的方法(即工厂方法)。如上面有关工厂方法模式的例子可以看出,工厂类中除了有抽象的,用于产品创建的工厂方法,还有其他的非抽象方法。这些非抽象的方法,往往是其他继承抽象工厂类的子类的通用方法。而抽象的工厂方法,则作为抽象方法延后到子类实现。因此工厂方法模式下,工厂类的角色并不单纯是生产产品,也包括了一些其他操作。

(2)工厂方法模式与抽象工厂模式都可以用于产品的创建,且符合开闭原则,不用每次新增新类型产品都修改工厂类。但工厂方法模式只能专注于某种产品的创建,而抽象工厂可以创建一系列的产品。

(3)工厂方法模式通过继承的方式,使子类继承基类并重写工厂方法;而抽象工厂模式,通过在抽象工厂接口中对工厂方法进行组合,从而实现创建多个类型产品的功能,更加灵活。

2.简单工厂模式、工厂方法模式和抽象工厂模式的使用场景

(1)简单工厂模式:工厂类负责创建的对象不多,且很少发生改变。
(2)工厂方法模式:需要考虑日后新增类型的产品,符合开闭原则。
(3)抽象工厂模式:需要考虑生产一系列类型的产品的创建。

3.关于开闭原则的一些思考

之前的例子中,对于简单工厂模式,如果有新增的产品,就要在工厂类的创建方法中修改switch逻辑,自然不符合“对扩展开放,对修改关闭”这一原则。但有的同学可能会对工厂方法模式和抽象工厂模式有疑问,因为在Client用户端调用工厂类的时候,肯定要指定某个具体的工厂子类来实例化,如果需要修改被实例化的具体工厂类,那么Client客户端的调用代码也需要改变,不符合开闭原则。

因此可行的方案是,工厂类的实例化,可以根据读取配置文件来完成。
比如我们可以在resources文件夹下新增配置文件如下:
“config.properties”

factory=factory.USAFactory

配置文件中通过自定义的"key=value"设置Client想要使用的具体工厂类型。

之后增加配置文件读取类以及对应的通过反射实例化具体工厂类型的方法,具体如下:
“GetInstance.java”

public class GetInstance {public static String getFactoryName(String fileName){String res = null;try{InputStream inputStream = GetInstance.class.getResourceAsStream(fileName);Properties properties = new Properties();properties.load(inputStream);res = properties.getProperty("factory");}catch (IOException e){e.printStackTrace();}return res;}public static BaseFactory getFactory(String className){try{return (BaseFactory) Class.forName(className).newInstance();}catch (Exception e){e.printStackTrace();return null;}}
}

最后,我们对Client的代码做一些修改,如下:
“Client.java”

public class Client {public static void main(String[] args) {BaseFactory factory = GetInstance.getFactory(GetInstance.getFactoryName("/config.properties"));Chair chair  = factory.createChair();Table table = factory.createTable();chair.sit();table.put();}
}

通过以上的方法,我们就可以通过修改配置文件中的内容选择实例化哪种具体工厂,防止对客户端代码进行修改了。
文章可能有不是很恰当的地方,感谢大家提出宝贵意见。

参考链接

工厂方法和抽象工厂的区别
工厂方法+配置文件
简单工厂模式

设计模式——简单工厂、工厂方法和抽象工厂的区别与联系相关推荐

  1. 设计模式:简单工厂、工厂方法、抽象工厂之小结与区别

    简单工厂,工厂方法,抽象工厂都属于设计模式中的创建型模式.其主要功能都是帮助我们把对象的实例化部分抽取了出来,优化了系统的架构,并且增强了系统的扩展性. 本文是本人对这三种模式学习后的一个小结以及对他 ...

  2. 【设计模式】简单工厂模式+工厂方法模式+抽象工厂模式

    前提导论 故事 不采用工厂模式 简单工厂模式 工厂方法模式 故事 抽象工厂模式 故事结局 前提导论 为了学习设计模式时便于理解,我将用基于农夫和他的村子与森林为背景环境,讲一个故事时,阐述一个设计模式 ...

  3. 【设计模式实战】简单工厂、工厂方法、抽象工厂:原理篇

    小明开发的应用,经常要从XML或者Asset中读取省市区数据. 小明是这样写的: public abstract class IOHandler {/*** 添加*/public abstract v ...

  4. 研磨23种大话设计模式------简单工厂模式 + 工厂方法模式 + 抽象工厂模式

    大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正 如果你从本文 get 到有用的干货知识,请帮忙点个赞呗,据说点赞的都拿到了offer 简 ...

  5. 【设计模式】Unity3D 简单工厂、工厂(方法)、抽象工厂模式

    创建型模式-工厂三兄弟 提示:个人学习总结,如有错误,敬请指正 文章目录 创建型模式---工厂三兄弟 一.简单工厂模式 1.简单工厂模式是什么? 2.UML图 3.实现方式 二.工厂(方法)模式 1. ...

  6. 设计模式学习笔记(三)简单工厂、工厂方法和抽象工厂之间的区别

    设计模式中的工厂模式(Factory Design pattern)是一个比较常用的创建型设计模式,其中可以细分为三种:简单工厂(Simple Factory).工厂方法(Factory Method ...

  7. 设计模式学习笔记(三)工厂模式中的简单工厂、工厂方法和抽象工厂模式之间的区别

    设计模式中的工厂模式(Factory Design pattern)是一个比较常用的创建型设计模式,其中可以细分为三种:简单工厂(Simple Factory).工厂方法(Factory Method ...

  8. 2.5万字详解23种设计模式—创建型模式(简单工厂、工厂方法、抽象工厂、单例-多线程安全详解、建造者、原型)的详细解读、UML类图

    本文简述了各大设计模式,并通过UML和代码详细说明.本文大约共 2.5W 字,建议收藏.下方是本文的目录: 一.设计模式的认识 二.设计模式的分类 根据其目的 根据范围 三.设计模式的优点 四.设计模 ...

  9. Android工厂设计模式(简单工厂,工厂方法,抽象工厂,BitmapFactory简单工厂分析,Retrofit抽象工厂分析)

    文章目录 创建型设计模式(简单工厂,工厂方法,抽象工厂) 一.简单工厂模式 引出简单工厂模式 二.工厂方法模式 三.抽象工厂模式 Android源码中用到的工厂模式举例 一.BitmapFactory ...

最新文章

  1. 10年卖下28家AI公司 苹果的AI吸星大法!
  2. java中static作用详解
  3. linux c 解析生成json(jansson安装和使用)
  4. Fabric核心模块之Peer解析
  5. 回归素材(part6)--机器学习系统设计
  6. 21_resultMap和resultType总结
  7. 嵌入式操作系统_航天科工海鹰翼辉嵌入式操作系统获自主原创“身份证”
  8. js 两个map合并为一个map_ArcGIS API for JS3.x教程二:构建第一个简单的程序
  9. Arduino笔记-Arduino UNO与WeMos D1串口通信(数据交互)
  10. 超实用!SKETCH大师最常用的3个实战小技巧
  11. 加服务器虚拟机软件,服务器虚拟机软件
  12. 上海自考计算机应用基础实践,上海自考《计算机应用基础》试题练习(八)
  13. 冬雷快递单打印软件anyPrint
  14. 漫游项目服务器,漫游Radius服务器的设计与实现
  15. java web程序设计任务教程——源码(全)
  16. TMK2SLNO TMK1SLNO 华为OSN1800 2路STM-16,8路STM-4或8路STM-1光接口板
  17. 状态码406解决方式
  18. JavaScript(基础)——初窥门径
  19. 电脑上最值得安装的软件,这10款里一定有你想要的
  20. 前台、后台、前端、后端的区分

热门文章

  1. Dreamweaver里怎么改图改字,怎么修改网页?
  2. 1月第2周全球域名总量TOP20:开曼群岛升至第九
  3. 爱情是什么? 婚姻是什么?
  4. linux mutt dns,使用mutt处理电子邮件
  5. 年度推荐书单:为你精选23本商业书
  6. 2022年山东省安全员C证新版试题及山东省安全员C证作业考试题库
  7. neo4j的关系节点如何添加属性信息
  8. 利用yum安装卸载软件常用命令
  9. linux主机名修改命令,Linux修改主机名的简单方法
  10. layui导航栏鼠标经过青色条块怎么移到顶部?