工厂模式
在java中,万物皆对象,这些对象的创建我们常用new来实现,方式比较简单,但是这种方式创建对象会使代码的耦合度比较高,如果要修改代码,那么我们需要重新再把所有的对象再new一遍,这是相当麻烦的事情,且不符合软件设计的开闭原则。如果使用工厂来代替我们自己创建对象,我们只需要跟工厂打交道就可以了,彻底和对象解耦,该模式有如下几种。
1 简单工厂模式
实际上简单工厂模式不算是一种设计模式,更像一种编程习惯,因其结构/角色简单明了而命名。简单工厂包含如下角色:
- 抽象产品:定义产品的规范
- 具体产品:实现或者继承抽象产品的子类
- 具体工厂:提供了创建产品的方法,通过该方法来获取产品对象
实现代码如下:
1.抽象产品
public interface Car{
void name();
}
2.具体产品
//WuLing.java
public class WuLing implements Car{
@Override
public void name() {
System.out.println("五菱");
}
}
//DaZhong.java
public class DaZhong implements Car{
@Override
public void name() {
System.out.println("大众");
}
}
//TesLa.java
public class TesLa implements Car{
@Override
public void name() {
System.out.println("特斯拉");
}
}
3.简单工厂
public class SimpleFactory{
//方式1(不常用)
public Car getCar(String car){
if ("五菱".equals(car)) {
return new WuLing();
} else if ("特斯拉".equals(car)) {
return new TesLa();
} else if ("大众".equals(car)) {
return new DaZhong();
} else {
return null;
}
}
//方式2(常用)
public static Car getWuLing() {
return new WuLing();
}
public static Car getDaZhong() {
return new DaZhong();
}
public static Car getTesLa() {
return new TesLa();
}
}
4.优缺点
优点:
- 封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避
- 免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户
- 代码修改的可能性,更加容易扩展
缺点:
- 增加新产品时还是要修改工厂类的代码,违背了“开闭原则”。
5.扩展
可以把工厂类的方法改为静态方法,这样就不需要手动new创建工厂类对象
public class SimpleFactory{
//方式1(不常用)
public static Car getCar(String car){
if ("五菱".equals(car)) {
return new WuLing();
} else if ("特斯拉".equals(car)) {
return new TesLa();
} else if ("大众".equals(car)) {
return new DaZhong();
} else {
return null;
}
}
...
}
2 工厂方法模式
1.概念:定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。使用工厂方法模式完美解决了违背开闭原则问题
2.本质:每一个产品对应自己的工厂(工厂用于生成该产品),这些工厂实现或者继承顶层的抽象工厂
3.结构:(角色)
- 抽象工厂:提供创建产品的接口(实际上就是方法),调用者通过访问具体工厂的方法来创建具体产品
- 具体工厂:主要实现抽象工厂中的抽象方法,完成具体的产品创建
- 抽象产品:定义了产品的规范,描述产品的特性和功能
- 具体产品:实现列抽象产品所定义的方法,由具体工厂来创建,它同具体工厂之间一一对应。
4.代码实现:
4.1 抽象产品
public interface Car {
void name();
}
4.2 具体产品
//WuLing.java
public class WuLing implements Car{
@Override
public void name() {
System.out.println("五菱");
}
}
//TesLa.java
public class TesLa implements Car{
@Override
public void name() {
System.out.println("特斯拉");
}
}
4.3 抽象工厂
public interface CarFactory {
Car getCar();
}
4.4 具体工厂
//五菱具体工厂
public class WuLingFactory implements CarFactory{
@Override
public Car getCar() {
return new WuLing();
}
}
//特斯拉具体工厂
public class TesLaFactory implements CarFactory{
@Override
public Car getCar() {
return new TesLa();
}
}
备注:调用者想要创建哪个对象,就调用对应的具体工厂的方法即可,如果想要添加新的具体产品,只需要添加对象的具体工厂和具体产品即可,不需要修改源代码,符合软件开发的开闭原则,但存在一个问题:这样会导致系统复杂,当产品过多时会产生类爆炸
3 抽象工厂方法模式
抽象工厂方法模式是工厂方法模式的升级版,其弥补了工厂方法只生成一种产品的限制,抽象工厂方法模式可以生产不同等级的产品,不同品牌的产品。(不同品牌<=>不同产品族,不同等级产品<=>不同级别产品)
本质:是围绕一个超级工程创建其他工厂,该超级工厂又称为其他工厂的工厂,这个超级工厂中定义所要生产的不同的产品等级的顶级接口
结构:
- 抽象工厂:提供创建产品的接口,包含多个创建产品的方法,可以创建不同等级的多个产品
- 具体工厂:主要实现抽象工厂中的多个抽象方法,完成具体的产品创建
- 抽象产品:定义产品的规范,描述产品的特性和功能,可以有多个抽象产品
- 具体产品:实现抽象产品所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系
实现:
1.抽象产品1
//抽象产品-手机
public interface IPhoneProduct {
void meg();
}
2.抽象产品2
//抽象产品-路由器
public interface IRouterProduct {
void msg();
}
3.具体产品-小米手机
public class XiaoMiIphone implements IPhoneProduct{
@Override
public void meg() {
System.out.println("小米手机");
}
}
4.具体产品-小米路由器
public class XiaoMIRouter implements IRouterProduct{
@Override
public void msg() {
System.out.println("小米路由");
}
}
5…抽象工厂-包含多个抽象产品的接口
public interface ProductFactory {
IPhoneProduct getIPhone();
IRouterProduct getIRouter();
}
6.具体工厂1-小米工厂
public class XiaoMiFactory implements ProductFactory{
@Override
public IPhoneProduct getIPhone() {
return new XiaoMiIphone();
}
@Override
public IRouterProduct getIRouter() {
return new XiaoMIRouter();
}
}
7.具体工厂2-华为工厂
//同上
8.测试类
public class Test {
public static void main(String[] args) {
XiaoMiFactory xiaoMiFactory = new XiaoMiFactory();
IPhoneProduct iPhone = xiaoMiFactory.getIPhone();
iPhone.meg();
}
}
备注:需要什么品牌系列的产品,只需要添加相应的具体工厂和具体产品类即可,不需要修改源代码,符合开闭原则
但如果新增的是产品结构等级,比如新增一个电视机,那么显示是要修改源代码且要修改顶层接口的源代码,这显然是不符合开闭原则的,因此该模式非常适合添加一个族系列相关产品。