文章中涉及到的代码,可到这里来拿:
https://gitee.com/daijiyong/DesignPattern
1.简单工厂模式
属于创建型模式
是指由一个工厂对象决定创建出哪一种产品类的实例
优点:只需要传入一个正确的参数,就可以获取你所需要的对象
类比一个生活场景
你到超市,只要你能准确说出你要买的东西是什么
售货员就能帮你找到并卖给你
你不需要关心他是怎么找到的、从哪进的货、怎么制造的
简单工厂模式适用于工厂类负责创建的对象较少,且基本不会变化
如果工厂类需要创建的产品频繁更新
势必要经常更改工厂类的内部代码
违反软件设计的开闭原则
针对创建一个课程的需求
一般一个学校的课程数量是很有限的
创建一个新的学科一般也比较难
所以这个场景就可以使用简单工厂模式
/**
* @author daijiyong
*/
public class CourseFactory {
public static ICourse create(Class<? extends ICourse> clazz) {
try {
if (null != clazz) {
return clazz.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
/**
* @author daijiyong
*/
public class Test {
public static void main(String[] args) {
ICourse course = CourseFactory.create(JavaCourse.class);
if (course != null) {
course.play();
}
}
}
举个栗子
Java的Calendar工具类采用的就是简单工厂模式
包括四个重载的创建方法
其实就是一个
点进去看看源码
/**
* Gets a calendar with the specified time zone and locale.
* The <code>Calendar</code> returned is based on the current time
* in the given time zone with the given locale.
*
* @param zone the time zone to use
* @param aLocale the locale for the week data
* @return a Calendar.
*/
public static Calendar getInstance(TimeZone zone,
Locale aLocale) {
return createCalendar(zone, aLocale);
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale) {
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}
从源码可以看出
Java的日历工具类,就是采用的工厂模式
工厂可以创建三个日历产品
分别是BuddhistCalendar、JapaneseImperialCalendar、GregorianCalendar
通过传入不同的时区参数,返回对应时区的日历
这个例子也很好的说明了简单工厂模式的使用场景
使用场景:工厂类负责创建的对象较少,且基本不会变化
地球估计一时半会儿是不会爆炸了
等到地球真爆炸了,Java还存不存在都是个未知数
所以频繁的变更时区的需求应该也没有了
这种情况下,就可以使用工厂模式
用户只需要传入一个参数,就可以得到想要的产品
不需要关系具体创建对象的逻辑
2.工厂方法模式
指定义一个创建对象的接口
但让实现这个接口的类来决定实例化哪个类
工厂让类的实例化推迟到子类中进行
属于创建型设计模式
只需要关心所需产品对应的工厂
而且即便加入新的产品,也符合开闭原则
所以他主要是为了解决简单工厂模式中产品扩展的问题
简单来说,就是根据单一职责设计原则
为不同的产品创建不同的工厂
而所有工厂实现一个借口,从而起到规范各个工厂的作用
具体常见产品的功能,由具体实现的工厂负责
/**
* @author daijiyong
*/
public class Test {
public static void main(String[] args) {
ICourseFactory courseFactory = new JavaCourseFactory();
ICourse course = courseFactory.create();
course.play();
}
}
再举个栗子
org.slf4j.ILoggerFactory就是用到工厂方法模式
每一个实现工厂类都有一个getLogger(String)的方法
这种模式在不违反开闭原则的情况下,又符合单一职责功能
简单来说,工厂方法模式就是工厂的工厂
3.抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,无需指定他们具体的类
属于创建型设计模式
一个产品族就是一个产品品牌,比如小米,比如格力等等
一个产品等级就是指一类产品,比如手机,比如电脑等等
每一个品牌需要一个具体的工厂生产他的产品族(小米生产手机、电脑等)
每一个产品具有多个产品等级结构(小米手机分为小米,红米;电脑分为小米、红米)
生产手机前,都需要先准备手机cpu、手机内存、手机显示屏
生产电脑前,也都需要先准备电脑cpu,电脑内存条,电脑显示器
下面就用抽象工厂模式实现一下
抽象工厂MiFactory中定义了一个成员方法和两个抽象方法
成员方法init()进行一些初始化操作
两个抽象方法的具体实现放到继承类当中
定义两个产品等级结构:手机和电脑
定义两个产品类族:红米和小米
定义四个产品:红米手机、红米电脑、小米手机、小米电脑
分别实现手机和电脑接口
调用的时候,只需指定是小米生产工厂
就可以生产相对应的电脑并使用电脑了
不需要知道具体是怎么实现
抽象工厂模式提供了一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖于具体实现
但是缺点就是增加了系统的抽象性和理解难度,扩展新的产品的时候,需要修改工厂的接口
4.总结
简单工厂:产品的工厂
工厂方法:工厂的工厂
抽象工厂:复杂产品的工厂
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式
有一点需要注意的地方就是复杂对象适合使用工厂模式
而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式
如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度
文/戴先生@2020年7月23日
---end---
更多精彩推荐