感觉工厂方法模式,是有点难理解的;所以先讲讲使用方法,再谈谈理解
定义
定义一个用于创建对象的接口,让子类决定实例化哪个类
使用场景
在任何需要生成复杂对象的地方,都可以使用工厂方法模式
举个栗子
比如数据存储,APP一般可以将数据保存在内存、数据库、服务器这三个地方;对数据的操作,一般就是增删改查,所以我们抽象出产品类;
public interface IoHandler {
/**
* 保存
*/
void save();
/**
* 删除
*/
void delete();
/**
* 更新
*/
void update();
}
然后具体产品类,就是实现接口保存数据到数据库
public class SqlLiteHandler implements IoHandler {
@Override
public void save() {
//保存数据到数据库
}
@Override
public void delete() {
}
@Override
public void update() {
}
}
就是实现接口保存数据到后台
public class ServerHandler implements IoHandler {
@Override
public void save() {
//保存数据到后台
}
@Override
public void delete() {
}
@Override
public void update() {
}
}
简单工厂模式
创建一个简单的工厂
public class IoFactory {
public static IoHandler getIoHandler(String type) {
IoHandler ioHandler = null;
if (type.equals("server")) {
ioHandler = new ServerHandler();
} else if (type.equals("sqllite")) {
ioHandler = new SqlLiteHandler();
}
return ioHandler;
}
}
调用也很简单
ServerHandler handler = IoFactory.getIoHandler("server");
工厂方法模式
上面的工厂有一个问题,不符合开闭原则,新增数据保存方式的时候需要修改IoFactory
,容易出错;解决方法,很简单,抽象出创建产品的接口
public interface IoFactory {
/**
* 创建IoHandler
* @return
*/
IoHandler createIoHandler();
}
实现接口,实现创建ServerHandler
的工厂,创建SqlLiteHandler
工厂方法也是一样
public class ServerFactory implements IoFactory {
@Override
public IoHandler createIoHandler() {
return new ServerHandler();
}
}
具体调用
ServerHandler handler = new ServerFactory().createIoHandler();
符合了开闭原则,新增一种保存方法不会影响之前的代码;每一个保存方法需要新建一个工厂,稍微有些麻烦,还有一种简洁的写法,利用反射来生产具体的对象
public interface IoFactory {
/**
* 创建IoHandler
*
* @param tClass
* @param <T>
* @return
*/
<T extends IoHandler> T createIoHandler(Class<T> tClass);
}
具体的工厂类通过反射就可以获取
public class IoHandlerFactory implements IoFactory {
@Override
public <T extends IoHandler> T createIoHandler(Class<T> tClass) {
IoHandler ioHandler = null;
try {
ioHandler = (IoHandler) Class.forName(tClass.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) ioHandler;
}
}
具体调用
ServerHandler serverHandler=new IoHandlerFactory().createIoHandler(ServerHandler.class);
SqlLiteHandler sqlLiteHandler=new IoHandlerFactory().createIoHandler(SqlLiteHandler.class);
抽象工厂模式
其实抽象工厂模式和工厂方法模式差不多,区别就是工厂方法模式一个工厂只能做一件事,比如创建一个IoHandler
对象;抽象工厂模式不只是创建一个IoHandler
,还得创建其他相关的对象出来;就是一个创建一组相关产品的工厂吧;实现方法和工厂方法模式一样,只是多了几种产品,抽象出来的工厂类多几个抽象方法,用来创建多的几个抽象产品,当然因为产品多了,实现的工厂类可以对产品进行组合,也更多了;
简单举个小例子
网上买电脑,CPU主板一起买会便宜不少,店铺一般也会给出几种搭配,我们选择其中一种就行了
抽象出CPU来
public interface Cpu {
/**
* CPU型号
* @return
*/
void cpuName();
}
AMD的1500X,ACpu
public class ACpu implements Cpu {
@Override
public void cpuName() {
System.out.println("Ryzen 5 1500X");
}
}
Intel的i7 9700k,ICpu
public class ICpu implements Cpu{
@Override
public void cpuName() {
System.out.println("i7 9700k");
}
}
抽象出主板来
public interface MotherBoard {
/**
* 主板型号
*
* @return
*/
void boardName();
}
Z390主板
public class BoardZ390 implements MotherBoard{
@Override
public void boardName() {
System.out.println("Z390-PLUS GAMING");
}
}
B250主板
public class BoardB250 implements MotherBoard{
@Override
public void boardName() {
System.out.println("MSI B250");
}
}
抽象出套餐工厂
public interface ComputerFactory {
/**
* 组装CPU
*
* @return
*/
Cpu buildCpu();
/**
* 组装主板
*
* @return
*/
MotherBoard buildBoard();
}
Z390主板加i7CPU的高配套装
public class HighwithFactory implements ComputerFactory {
@Override
public Cpu buildCpu() {
return new ICpu();
}
@Override
public MotherBoard buildBoard() {
return new BoardZ390();
}
}
B250主板加上1500X的中配套餐
public class MediumFactory implements ComputerFactory {
@Override
public Cpu buildCpu() {
return new ACpu();
}
@Override
public MotherBoard buildBoard() {
return new BoardB250();
}
}
现在要选择高配的套餐
ComputerFactory computerFactory=new HighwithFactory();
computerFactory.buildBoard().boardName();
computerFactory.buildCpu().cpuName();
输出
Z390-PLUS GAMING
i7 9700k
但是当我把显卡、内存条、硬盘、机箱都加进来,高低配硬件也进行组合,组合就会变得很多,而套餐(工厂)就会变得非常多,就会创建非常多的类,因此开发中需要谨慎使用
工厂方法的理解
需要抽象出产品,抽象出工厂,实现不同的工厂去创建不同的产品;抽象这种东西,在六大基本原则就知道了,抽象是要抽象的,问题是为什么还需要一个工厂呢,直接new一个产品不行吗?感觉像是构造者模式的Director部分一样,没什么用呀
有这个疑问也很正常,我在看了这篇文章(工厂设计模式有什么用?)后,好像有了一点点理解;本质上是封装了new一个具体的classA
的细节,将变化控制在工厂之中;如果classA
的构造改变了,或者需要改为使用classB
了,可以在工厂方法里面修改而不需要修改调用者,这样实现解耦,遵循开闭原则
我感觉好像和依赖注入差不多一个意思,我们为了不耦合,所以不自己去创建对象,使用注入进来的对象,现在我们为了不耦合也可以使用工厂注入对象,可能差不多吧
总结
感觉大概多使用就理解了吧
网友评论