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

举报
SHQ5785 发表于 2020/12/29 23:53:38 2020/12/29
【摘要】 #大话设计模式(八)抽象工厂模式进化 ##前情回顾   在博文《大话设计模式(七)抽象工厂模式》中,我们了解了抽象工厂设计模式。在讲解反射机制时,我们提到反射机制实现了程序由编译时到运行时变量的指定。我们的设计不能防止需求的更改,那么我们的理想就是让变动变得最小。结合前面的代码讲解,当我们需要增加产品C时,那么我们就需要增加3个类。并修改3个类。 //抽象产品C,定义...

#大话设计模式(八)抽象工厂模式进化
##前情回顾
  在博文《大话设计模式(七)抽象工厂模式》中,我们了解了抽象工厂设计模式。在讲解反射机制时,我们提到反射机制实现了程序由编译时到运行时变量的指定。我们的设计不能防止需求的更改,那么我们的理想就是让变动变得最小。结合前面的代码讲解,当我们需要增加产品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();
	}
} 

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

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

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();
	}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

  我们通过利用简单工厂模式,抛弃了抽象工厂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();
	}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

##优化之配置文件+反射
  这么写的话还是有点缺憾,因为在更换生成对象的时候,还是需要去改程序(改这个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();
	}

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

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

implClass=cn.edu.ujn.designpattern.Apple

  
 
  • 1

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

![这里写图片描述](https://img-blog.csdnimg.cn/img_convert/defc883f0a73a1117eef26e9bd37ad64.png) ![这里写图片描述](https://img-blog.csdnimg.cn/img_convert/ad74b5f56b7d34a7fcf99cfacfacb9e5.png) ![这里写图片描述](https://img-blog.csdnimg.cn/img_convert/e54049c3181bf5d9062cc85e10dc0fc1.png)

文章来源: shq5785.blog.csdn.net,作者:No Silver Bullet,版权归原作者所有,如需转载,请联系作者。

原文链接:shq5785.blog.csdn.net/article/details/52781589

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。