前言
- 内容搜集于网上多篇优秀文章,结合自己理解,写下该文
介绍
- 工厂模式有三种类型:简单工厂模式、工厂模式 、抽象工厂模式
- 都属于类的创建型模式
- 创建对象的逻辑在工厂中,不会对外暴露创建逻辑
应用场景
- 凡是需要生成复杂实例的地方,都可以尝试考虑使用工厂模式来代替
我的应用场景
- 文件操作
- 文件操作接口定义所有文件上传的共同行为:上传、下载、删除…
- 三个文件操作的实现:monio、fastdfs、本地
- 工厂类返回不同的文件操作的实例
一、简单工厂模式
介绍
- 简单工厂模式专门定义一个工厂类来负责创建其他类的实例,可以根据参数的不同返回不同类的实例,返回值一般是一个接口、抽象类,所以被创建的实例通常都具有共同的父类、实现共同的接口
- 在简单工厂模式中创建实例的方法通常为静态方法,所以又叫静态工厂方法模式
优点
- 低耦合:如果类的构造过于复杂,直接在其他业务类内使用,当该对象的构造过程发生改变,就需要一个一个查找该对象并修改,对象的创建和业务类耦合严重;用工厂类生产对象来代替对象的构造过程,在业务逻辑处不会暴漏具体类,所以无需修改获取产品、使用产品的代码,只需改变工厂类的生产逻辑即可
缺点
- 违背了 “开闭原则”,新增一个产品就需要修改工厂获取实例的方法
角色
- 抽象产品:接口或抽象类,定义了产品共同的行为
- 具体产品:抽象产品的实现,实现或继承抽象产品,实现具体的行为
- 具体工厂:提供创建产品的方法,工厂类可以被外界直接调用,创建所需产品
代码实现
一、普通
1.创建产品接口
public interface ITennis{
void play();
}
2.创建产品的实现
public class BabolatTennisImpl implements ITennis{
@Override
public void play(){
System.err.println("play babolat tennis");
}
}
public class HeadTennisImpl implements ITennis{
@Override
public void play(){
System.err.println("play head tennis");
}
}
3.创建生产产品实例的工厂
public class TennisFactory{
public enum TennisBrand{
BABOLAT,
HEAD;
}
public static ITennis getTennis(TennisBrand tennisBrand){
switch(tennisBrand){
case BABOLAT:
return new BabolatTennisImpl();
case HEAD:
return new HeadTennisImpl();
}
return null;
}
}
4.生成实例
ITennis tennis=TennisFactory.getTennis(TennisFactory.TennisBrand.BABOLAT);
二、Spring
1.抽象产品
public interface ITennis{
void play();
}
2.具体产品
@Service("BABOLAT")
public class BabolatTennisImpl implements ITennis{
@Override
public void play(){
System.err.println("play babolat tennis");
}
}
@Service("HEAD")
public class HeadTennisImpl implements ITennis{
@Override
public void play(){
System.err.println("play head tennis");
}
}
3.具体工厂
@Component
public class TennisFactory{
@Autowired
private Map<String,ITennis> tennisMap;
public enum TennisBrand{
BABOLAT,
HEAD;
}
public ITennis getTennisInstance(TennisBrand tennisBrand){
return tennisMap.get(tennisBrand.name());
}
}
4.生成实例
@Resource
private TennisFactory tennisFactory;
tennisFactory.getTennisInstance(TennisFactory.TennisBrand.BABOLAT);
二、工厂方法模式
优点
- 简单工厂模式有一个问题就是,类的创建依赖工厂类,如果增加了一种产品实现,就必须对工厂类返回产品实例的方法进行修改,工厂方法解决了这个问题
- 遵循"开闭原则",增加抽象工厂、每个产品增加对应工厂类,每个工厂类实现生产对应产品,这样再增加产品时,只需增加一个包,在其中增加产品实现、产品工厂实现即可,而无需修改任何代码
角色
- 抽象产品:接口或抽象类,定义了产品共同的行为
- 抽象工厂:提供创建产品的抽象方法
- 具体产品:抽象产品的实现,实现或继承抽象产品,实现具体的行为
- 具体工厂:抽象工厂的实现,每个具体产品都对应一个具体工厂,生产对应的具体产品实例
代码实现
1.抽象产品
public interface ITennis{
void play();
}
2.抽象工厂
public interface ITennisFactory{
ITennis getTennisInstance();
}
3.具体产品
public class BabolatTennis implements ITennis{
BabolatTennis(){
}
@Override
public void play(){
System.err.println("play babolat tennis");
}
}
4.具体工厂
public class BabolatTennisFactory implements ITennisFactory{
@Override
public ITennis getTennisInstance(){
return new BabolatTennis();
}
}
5.生成实例
TennisFactory babolatFactory=new BabolatTennisFactory();
ITennis babolatTennis=babolatFactory.getTennisInstance();
babolatTennis.play();
三、抽象工厂方法模式
介绍
- 抽象工厂模式是工厂方法模式的升级版本。与工厂方法模式的区别在于:工厂方法模式针对的是一个产品结构;而抽象工厂模式则是针对的一组产品结构
- 工厂方法有一个问题:增加一种产品,就要增加抽象产品、抽象工厂、具体产品、具体工厂。有的时候产品之间是有关系的,更像是一组产品,例如网球、网球拍。不区分厂商而是归为一类产品的叫做产品族。海德生产网球、网球拍,它们属于同一个厂商
角色
- 抽象产品:接口或抽象类,定义了产品共同的行为,这里是多个抽象产品类
- 抽象工厂:提供创建产品的抽象方法,这里是多个创建产品的抽象方法
- 具体产品:抽象产品的实现,实现或继承抽象产品,实现具体的行为,这里会多个具体产品类
- 具体工厂:抽象工厂的实现,生产对应的产品的实例,这里会多个生产产品的方法
代码实现
1.抽象产品
public interface ITennis{
void play();
}
public interface ITennisRacket{
void use();
}
2.抽象工厂
public interface ITennisFactory{
ITennis getTennisInstance();
ITennisRacket getTennisRacketInstance();
}
3.具体产品
public class BabolatTennis implements ITennis{
BabolatTennis(){
}
@Override
public void play(){
System.err.println("play babolat tennis");
}
}
public class BabolatRacketTennis implements ITennisRacket{
BabolatRacketTennis(){
}
@Override
public void use(){
System.err.println("use babolat tennis racket");
}
}
4.具体工厂
public class BabolatTennisFactory implements ITennisFactory{
@Override
public ITennis getTennisInstance(){
return new BabolatTennis();
}
@Override
public ITennisRacket getTennisRacketInstance(){
return new BabolatRacketTennis();
}
}
5.生成实例
ITennisFactory babolatFactory=new BabolatTennisFactory();
ITennisRacket babolatTennisRacket=babolatFactory.getTennisRacketInstance();
babolatTennisRacket.use();
ITennis babolatTennis=babolatFactory.getTennisInstance();
babolatTennis.play();