目录
- 前言
- 一、简单工厂模式
- 1、工厂类
- 2、优化工厂
- 3、再优化工厂
- 二、工厂方法模式
- 三、抽象工厂
前言
工厂就是生产各种各样东西的地方,在代码中,就是创建一个个类。对于简单的类而言,我们直接new一个。但是对于一系列对象,或者对象创建需要很多额外的操作,我们需要集中的管理起来。比如new的时候需要初始化各种各样的参数、或者要调用很多其他的方法等等。我们每次new这个对象,都会重复做这么多繁琐的操作。久了会让人恶心头晕。现在我们要升华一下我们的代码。
一、简单工厂模式
举个栗子🌰:当我们需要水果这个对象,水果有苹果、香蕉、草莓、葡萄…等等对象的时候。
// 原来我们需要这么写
Apple apple = new Apple();
Banana banana = new Banana();
现在我们把生产水果封装到一个工厂中。
苹果香蕉都属于水果,所以我们需要一个水果的接口
/**
* 水果类
*/
public interface Fruits {
/**
* 获取名称
* @return
*/
void getName();
}
苹果香蕉对应的实现该接口
public class AppleFruits implements Fruits {
public void getName() {
System.out.println("苹果");
}
}
public class BananaFruits implements Fruits {
@Override
public void getName() {
System.out.println("香蕉");
}
}
1、工厂类
public class FruitsFactory {
public Fruits create(String name){
if("apple".equals(name)){
return new AppleFruits();
}else if("banana".equals(name)){
return new BananaFruits();
}else {
return null;
}
}
}
这样我们在使用的时候,完全不用关心 AppleFruits
,BananaFruits
这些具体得水果。
FruitsFactory factory = new FruitsFactory();
Fruits fruits = factory.create("apple");
fruits.getName();
但是这样如果我们要新增一种水果,就要修改FruitsFactory
类,多加一个if..else
,这明显是不符合开闭原则的。所以我们可以升级一下。修改我们的工厂类。
2、优化工厂
public Fruits create(String className){
try {
if (!(null == className || "".equals(className))) {
return (Fruits) Class.forName(className).newInstance();
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
这样我们在使用的时候只需要填写对应的类名。
FruitsFactory factory = new FruitsFactory();
Fruits fruits = factory.create("com.machuxin.AppleFruits");
fruits.getName();
好处:新增水果的时候,不需要修改工厂类FruitsFactory
缺点:com.machuxin.AppleFruits
这个长的参数是什么鬼??
3、再优化工厂
public Fruits create(Class<? extends Fruits> clazz) {
try {
if (null != clazz) {
return clazz.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
这样我们填写参数的时候,只要对应的class即可。
FruitsFactory factory = new FruitsFactory();
Fruits fruits = factory.create(AppleFruits.class);
fruits.getName();
这样参数不存在拼写的错误。后期拓展只需要对应的class实现Fruits
类即可。
二、工厂方法模式
当水果越来越多,水果工厂就会越来越臃肿,什么水果都能生产,成了万能水果厂。这样不符合职责单一原则。我们希望苹果工厂只生产苹果、香蕉工厂只生产香蕉。于是对工厂进行抽象。
/**
* 工厂模型
*/
public interface FruitsFactory {
Fruits create();
}
/**
* 苹果厂只生产苹果
*/
public class AppleFactory implements FruitsFactory {
public Fruits create() {
return new AppleFruits();
}
}
/**
* 香蕉厂只生产香蕉
*/
public class BananaFactory implements FruitsFactory {
public Fruits create() {
return new BananaFruits();
}
}
测试使用
public static void main(String[] args) {
FruitsFactory factory = new AppleFactory();
Fruits fruits = factory.create();
fruits.getName();
factory = new BananaFactory();
fruits = factory.create();
fruits.getName();
}
工厂模式适合场景:
- 创建对象需要大量重复代码
- 客户端(应用层) 不依赖与产品实例如何创建、实现等细节
- 通过自类来决定创建那个对象
缺点:
1、类的个数多,复杂度高。
2、增加系统的抽象性,理解难度高
三、抽象工厂
随着产品的种类越来越多,产品的等级越来越高。为方便统一整理,便出现了抽象工厂。我们先来梳理一下产品族与等级。
水果分为苹果、香蕉、葡萄。同样苹果也分为A级苹果(红苹果)、B级苹果(青苹果)、C类苹果(紫苹果)
于是我们的工厂将可想横向、纵向,两个方向进行可扩展。
public abstract class AbstractFruitsFactory {
protected abstract IColor color();
protected abstract ISize size();
}
水果有颜色还有大小两个方法。
/**
* 颜色
*/
public interface IColor {
void getColor();
}
/**
* 大小
*/
public interface ISize {
void getSize();
}
苹果工厂继承抽象工厂,实现大小与颜色2个接口。
public class AppleFactory extends AbstractFruitsFactory {
@Override
protected IColor color() {
return new AppleColor();
}
@Override
protected ISize size() {
return new AppleSize();
}
}
苹果大小接口
public class AppleSize implements ISize {
@Override
public void getSize() {
System.out.println("1斤");
}
}
苹果颜色接口
public class AppleColor implements IColor{
@Override
public void getColor() {
System.out.println("红色");
}
}
使用实例
AppleFactory factory = new AppleFactory();
factory.color().getColor();
factory.size().getSize();
如果所示,我们通过继承AbstractFruitsFactory
对水果产品种类实现了横向扩展,同时,对IColor
、ISize
等接口的实现提供了纵向的扩展。
缺点:如果要增加纵向功能,如重量,需要对AbstractFruitsFactory
接口进行修改。这不符合我们的开闭原则
。但实际生活中,这是一件比较正常的事,只要修改不频繁,我们是可以容忍的。还好JAVA8 提供default 关键字,允许父类采用默认实现。改动量大大减小了。
至此,工厂模式已经完成了,如果有理解不到位的地方,欢迎大家指教。
源码地址:https://gitee.com/xiaowangz/learning-note