大话设计模式(八)抽象工厂模式进化

一、前情回顾

在博文《大话设计模式(七)抽象工厂模式》中,我们了解了抽象工厂设计模式。在讲解反射机制时,我们提到反射机制实现了程序由编译时到运行时变量的指定。我们的设计不能防止需求的更改,那么我们的理想就是让变动变得最小。结合前面的代码讲解,当我们需要增加产品C时,那么我们就需要增加3个类。并修改3个类。

//抽象产品C,定义了产品的公共方法,产品A、B和C属于一个产品族  
interface ProductC {
	public void method1();

	public void method2();
}
// 等级为1的具体产品C
class ConcreateProductC1 implements ProductC {

	@Override
	public void method1() {
		System.out.println("等级为1的产品C的method1()");
	}

	@Override
	public void method2() {
		System.out.println("等级为1的产品C的method2()");
	}
}

// 等级为2的具体产品C
class ConcreateProductC2 implements ProductC {

	@Override
	public void method1() {
		System.out.println("等级为2的产品C的method1()");
	}

	@Override
	public void method2() {
		System.out.println("等级为2的产品C的method2()");
	}
}
// 修改
//抽象工厂,定义了生产族产品的方法;  
interface AbstractFactory_ {  
	public ProductA factoryA();  
	public ProductB factoryB();  
public ProductC factoryC(); 
}

// 具体工厂(生产等级为1的族产品)
class ConcreateFactory1 implements AbstractFactory_ {

	// 生产等级为1的产品A
	@Override
	public ProductA factoryA() {
		return new ConcreateProductA1();
	}

	// 生产等级为1的产品B
	@Override
	public ProductB factoryB() {
		return new ConcreateProductB1();
	}

	// 生产等级为1的产品C
	@Override
	public ProductC factoryC() {
		return new ConcreateProductC1();
	}

} 

//具体工厂(生产等级为2的族产品)
class ConcreateFactory2 implements AbstractFactory_ {

	// 生产等级为2的产品A
	@Override
	public ProductA factoryA() {
		return new ConcreateProductA2();
	}

	// 生产等级为2的产品B
	@Override
	public ProductB factoryB() {
		return new ConcreateProductB2();
	}
	// 生产等级为2的产品C
	@Override
	public ProductC factoryC() {
		return new ConcreateProductC2();
	}
} 

二、优化之简单工厂模式

可见,对于程序的扩展性、灵活性提出了严峻的挑战。为此,我们可以使用简单工厂模式来进行重新设计。

package cn.edu.ujn.designpattern;

class ProductAccess{
//	private static String name = "A1"; 
	private static String name = "A2"; 
//	private static String name = "B1";
//	private static String name = "B2"; 
//	private static String name = "C";
	public static AbstractFactory_ creatProduct(){
		AbstractFactory_ result = null;
		switch (name) {
			case "A1":
				result = new ConcreateFactory1();
				ProductA productA1 = new ConcreateProductA1();
				productA1.method1();
				break;
			case "A2":
				result = new ConcreateFactory1();
				ProductA productA2 = new ConcreateProductA2();
				productA2.method2();
				break;
			case "B1":
				ProductB productB1 = new ConcreateProductB1();
				productB1.method1();
				break;
			case "B2":
				ProductB productB2 = new ConcreateProductB2();
				productB2.method2();
				break;
/*			case "C1":
				ProductC productC1 = new ConcreateProductC1();
				productC1.method1();
				break;	*/		
		}
		return result;
	}
}

public class AbstractFactory_Modified {
	public static void main(String[] args) {
		ProductAccess.creatProduct();
	}
}

我们通过利用简单工厂模式,抛弃了抽象工厂AbstractFactory_、抽象角色ProductA、ProductB、ProductC等若干个工厂类,取而代之的是ProductAccess类,由于事先设置了name的值(A1、A2、B1、B2、C1、C2),所以简单工厂的方法都不需要输入参数,这样在客户端就只需要ProductAccess.creatProduct();来生成具体的产品实例,客户端没有出现任何一个A1、A2、B1、B2、C1、C2的字样,达到了解耦的目的。

三、优化之反射机制

但是,问题依旧存在。如果我们需要增加产品D获取,这样就需要在ProductAccess类中增加case了,同单例模式存在一样的问题:违反了OCP原则。为此,我们可以通过使用反射+单例模式实现。

package cn.edu.ujn.designpattern;

class Fruit_Factory {
    
    /**
     * 获取实例
     * @param productName 实体
     * @return
     */
    public static Fruit createAnimal(String fullName){
        try {
            // 通过反射获取实例,通过给定类的字符串名称获取该类,类的全名
            Class clazz = Class.forName(fullName);
            try {
                return (Fruit) clazz.newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException("实例化异常!",e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("这个实体类不存在!",e);
        }
    }
}

public class SimpleFactory_Reflection {

	public static void main(String[] args) {
	     //测试
		String className = "cn.edu.ujn.designpattern.Apple"; 
		Fruit apple = (Fruit) Fruit_Factory.createAnimal(className);				apple.grow();
	}
}

四、优化之配置文件+反射

这么写的话还是有点缺憾,因为在更换生成对象的时候,还是需要去改程序(改这个className的值)重编译,如果可以不改程序,那才是真正的符合OCP。为此,我们可以利用配置文件来解决更改的问题。

package cn.edu.ujn.designpattern;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

class Fruit_Factory {
    
    /**
     * 获取实例
     * @param productName 实体
     * @return
     */
    public static Fruit createFruit(){
    	
    	  Properties pro = new Properties();

          InputStream ins;

          ins = Fruit.class.getResourceAsStream("factory.properties");
          try {
              pro.load(ins);
          } catch (IOException e) {
              e.printStackTrace();
          } finally{
        	  try {
				ins.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
          }

          String implClassStr = pro.get("implClass").toString();
    	
        try {
            // 通过反射获取实例,通过给定类的字符串名称获取该类,类的全名
            Class clazz = Class.forName(implClassStr);
            try {
                return (Fruit) clazz.newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException("实例化异常!",e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("这个实体类不存在!",e);
        }
    }
}

public class SimpleFactory_Reflection {

	public static void main(String[] args) {
	     //测试
		String className = "cn.edu.ujn.designpattern.Apple"; 
		Fruit apple = (Fruit) Fruit_Factory.createFruit();
		apple.grow();
	}

}

可添加一个配置文件factory.properties,内容如下:

implClass=cn.edu.ujn.designpattern.Apple

从这个角度上看,所有在使用简单工厂的地方,都可以考虑使用反射技术去除switch或if,解除分支判断带来的耦合,使之更加容易维护和扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

No Silver Bullet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值