大家好,欢迎来到IT知识分享网。
一、前情回顾
在博文《大话设计模式(七)抽象工厂模式》中,我们了解了抽象工厂设计模式。在讲解反射机制时,我们提到反射机制实现了程序由编译时到运行时变量的指定。我们的设计不能防止需求的更改,那么我们的理想就是让变动变得最小。结合前面的代码讲解,当我们需要增加产品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,解除分支判断带来的耦合,使之更加容易维护和扩展。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/26519.html