工厂模式是用工厂方法代替了new操作, 将选择实现类
, 创建对象
统一管理和控制.从而将调用者(Client)与实现类进行解耦.实现了创建者与调用者分离
;
java中的工厂模式又有三种模式,分别是静态工厂、工厂模式和抽象模式。
使用场景:
- JDK中Calendar的getInstance方法;
- JDBC中Connection对象的获取;
- MyBatis中SqlSessionFactory创建SqlSession;
- SpringIoC容器创建并管理Bean对象;
- 反射Class对象的newInstance;
- ….
一、静态工厂
静态工厂模式是工厂模式中最简单的一种,他可以用比较简单的方式隐藏创建对象的细节,一般只需要告诉工厂类所需要的类型,工厂类就会返回需要的产品类,而客户端看到的也只是产品的抽象对象(interface),因此无需关心到底是返回了哪个子类
1、接口类
实现一个产品工厂,有两种产品分别是A、B,使用静态工厂完成产品的信息输出。
在接口中定义方法描述每种产品的信息
package com.lq.demo;
public interface IProduct {
//描述每种产品的信息
public void desc();
}
2、产品A
重写接口的方法,实现产品A的信息输出
package com.lq.demo;
public class ProductA implements IProduct{
@Override
public void desc() {
System.out.println("产品A的编号是001,名称是A,最大金额是10000");
}
}
3、产品B
重写接口的方法,实现产品B的信息输出
package com.lq.demo;
public class ProductB implements IProduct{
@Override
public void desc() {
System.out.println("产品B的编号是002,名称是B,最大金额是20000");
}
}
4.产品工厂
在工厂中定义产品类型,通过传入的值判断具体的产品
package com.lq.demo;
public class ProductFactory {
public static int type_A = 1;//产品A
public static int type_B = 2;//产品B
public static IProduct createProduct(int type){
switch(type){
case 1:
return new ProductA();
case 2:
default:
return new ProductB();
}
}
}
5.测试类
package com.lq.test;
import com.lq.demo.IProduct;
import com.lq.demo.ProductFactory;
public class TestProduct {
public static void main(String[] args) {
//选择了产品A
IProduct p = ProductFactory.createProduct(ProductFactory.type_A);
p.desc();
}
}
测试结果:
-
优点
- 隐藏了对象创建的细节,将产品的实例化过程放到了工厂中实现。
- 客户端基本不用关心使用的是哪个产品,只需要知道用工厂的那个方法(或传入什么参数)就行了.
- 方便添加新的产品子类,每次只需要修改工厂类传递的类型值就行了。
- 遵循了
依赖倒转
原则。
-
缺点
- 适用于产品子类型差不多, 使用的方法名都相同的情况.
- 每添加一个产品子类,都必须在工厂类中添加一个判断分支(或一个方法),这违背了
OCP(开放-封闭原则)
。
二、工厂模式
工厂模式会提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例。
提供一个产品类的接口。产品类均要实现这个接口(也可以是abstract类,即抽象产品)。
提供一个工厂类的接口。工厂类均要实现这个接口(即抽象工厂)。
由工厂实现类创建产品类的实例。工厂实现类应有一个方法,用来实例化产品类。
1、产品接口
实现产品的信息输出
package com.lq.demo;
public interface IProduct {
public void desc();
}
2、产品A
package com.lq.demo;
public class ProductA implements IProduct{
@Override
public void desc() {
System.out.println("产品类型是A,产品编号是001,最大金额是10000");
}
}
3、产品B
package com.lq.demo;
public class ProductB implements IProduct{
@Override
public void desc() {
System.out.println("产品类型是B,产品编号是002,最大金额是20000");
}
}
4、工厂接口
通过工厂接口创建工厂实例
package com.lq.demo;
public interface IProductFactory {
public IProduct createProduct(String type);
}
5、工厂实例
package com.lq.demo;
public class ProductFactory implements IProductFactory{
@Override
public IProduct createProduct(String type) {
IProduct product;
if(type.equals("A")){
product = new ProductA();
}else if(type.equals("B")){
product = new ProductB();
}else{
System.out.println("产品不存在,因此默认生产A");
product = new ProductA();
}
return product;
}
}
6、测试类
package com.lq.test;
import com.lq.demo.IProduct;
import com.lq.demo.IProductFactory;
import com.lq.demo.ProductFactory;
public class TestFactory {
public static void main(String[] args) {
//创建工厂
IProductFactory factory = new ProductFactory();
//通过工厂创建产品实例
IProduct product;
//创建产品A
product = factory.createProduct("A");
product.desc();
//创建产品B
product = factory.createProduct("B");
product.desc();
}
}
优点
基本与静态工厂模式一致,多的一点优点就是遵循了开放-封闭原则,使得模式的灵活性更强。
缺点
与静态工厂模式差不多, 但是增加了类组织的复杂性;
小结
虽然根据理论原则, 需要使用工厂方法模式, 但实际上, 常用的还是静态工厂模式.
三、抽象工厂
抽象工厂模式: 提供一个创建一系列相关或相互依赖对象的接口, 而无需指定他们具体的类.
抽象工厂模式与工厂方法模式的区别:
- 抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构, 在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类
1、产品的编号接口
package com.lq.demo;
public interface IProductNumber {
public void getNumber();
}
class ProductANumber implements IProductNumber{
@Override
public void getNumber() {
System.out.println("产品编号是001");
}
}
class ProductBNumber implements IProductNumber{
@Override
public void getNumber() {
System.out.println("产品编号是002");
}
}
2、产品的名称接口
package com.lq.demo;
public interface IProductName {
public void getName();
}
class ProductAName implements IProductName{
@Override
public void getName() {
System.out.println("产品名称是A");
}
}
class ProductBName implements IProductName{
@Override
public void getName() {
System.out.println("产品名称是B");
}
}
3、产品的金额接口
package com.lq.demo;
public interface IProductMoney {
public void getMax();
}
class ProductAMoney implements IProductMoney{
@Override
public void getMax() {
System.out.println("最大金额是10000");
}
}
class ProductBMoney implements IProductMoney{
@Override
public void getMax() {
System.out.println("最大金额是20000");
}
}
4、产品工厂
package com.lq.demo;
public interface IProduct {
public IProductNumber getNumber();
public IProductName getName();
public IProductMoney getMoney();
}
5、产品具体实现类A、B
package com.lq.demo;
public class ProductA implements IProduct{
@Override
public IProductNumber getNumber() {
return new ProductANumber();
}
@Override
public IProductName getName() {
return new ProductAName();
}
@Override
public IProductMoney getMoney() {
return new ProductAMoney();
}
}
package com.lq.demo;
public class ProductB implements IProduct{
@Override
public IProductNumber getNumber() {
return new ProductBNumber();
}
@Override
public IProductName getName() {
return new ProductBName();
}
@Override
public IProductMoney getMoney() {
return new ProductBMoney();
}
}
6、测试
package com.lq.test;
import com.lq.demo.IProduct;
import com.lq.demo.ProductA;
public class TestProduct {
public static void main(String[] args) {
//实例化产品A
IProduct A = new ProductA();
A.getNumber().getNumber();;
A.getName().getName();;
A.getMoney().getMax();;
}
}
结果:
- 优点
- 封装了产品的创建,使得不需要知道具体是哪种产品,只需要知道是哪个工厂就行了。
- 可以支持不同类型的产品,使得模式灵活性更强。
- 可以非常方便的使用一族中间的不同类型的产品。
- 缺点
- 结构太过臃肿,如果产品类型比较多,或者产品族类比较多,就会非常难于管理。
- 每次如果添加一组产品,那么所有的工厂类都必须添加一个方法,这样违背了开放-封闭原则。所以一般适用于产品组合产品族变化不大的情况。
参考博客:
https://www.cnblogs.com/zailushang1996/p/8601808.html
https://blog.csdn.net/qq_21036901/article/details/81080420