以下为java抽象工厂模式的一个例子,都是个人的一点想法,有什么不足的地方,恳求大家予以指出,欢迎讨论
我们使用的界面上有
文本 {Linux文本,Windows文本}
标签 {Linux标签,Windows标签}
等等.
第一部分 抽象工厂的实现
interface 文本 {}
interface 标签 {}
class Linux文本 implements 文本{
public String toString() {
return "Linux文本";
}
}
class Linux标签 implements 标签{
public String toString() {
return "Linux标签";
}
}
class Windows文本 implements 文本{
public String toString() {
return "Windows文本";
}
}
class Windows标签 implements 标签{
public String toString() {
return "Windows标签";
}
}
interface 组件工厂 {
public 文本 生产文本组件();
public 标签 生产标签组件();
}
class Linux组件工厂 implements 组件工厂 {
public 文本 生产文本组件() {
return new Linux文本();
}
public 标签 生产标签组件() {
return new Linux标签();
}
}
class Windows标签组件工厂 implements 组件工厂 {
public 文本 生产文本组件() {
return new Windows文本();
}
public 标签 生产标签组件() {
return new Windows标签();
}
}
class 客户系统显示 {
private 文本 text;
private 标签 label;
public static void main(String args[]) {
客户系统显示 clientOS = new 客户系统显示();
组件工厂 factory = new Linux组件工厂();
clientOS.label = factory.生产标签组件();
clientOS.text = factory.生产文本组件();
System.out.println(clientOS.label);
System.out.println(clientOS.text);
}
}
如果按照上面的标准,我们要添加一个新的组件 下拉框
A.需要修改的地方有
1.组件工厂
2.Linux组件工厂
3.Windows标签组件工厂
B.需要增加的有
1.interface 下拉框 {}
2.class Linux下拉框 implements 下拉框
3.class Windows下拉框 implements 下拉框
C.调用的地方也会多出一个factory.生产下拉框组件();
第二部分 改革抽象工厂
有没有觉得要改动的地方有点多呢,下面我们来改革一下
1.把 组件工厂中的
生产文本组件();
生产标签组件();
...
都改为
生产组件(组件标识);
这样带来的好处就是前面提到的,以下的修改就免去了
/**************************/
......
A.需要修改的地方有
1.组件工厂
2.Linux组件工厂
3.Windows标签组件工厂
......
/**************************/
要做到上面的,需要做以下几件事情
1.增加一个Annotation来说明后面增加的 组件注册表
@interface 组件描述 {
Class 组件类();
}
2.增加一个Enum
enum 组件注册表 {
/**
* Linux_文本 的对应实体类为 Linux文本
*/
@组件描述(组件类 = Linux文本.class)
Linux_文本,
@组件描述(组件类 = Linux标签.class)
Linux_标签,
@组件描述(组件类 = Windows文本.class)
Windows_文本,
@组件描述(组件类 = Windows标签.class)
Windows_标签,
}
3.我们不再需要
interface 组件工厂,class Windows标签组件工厂,class Linux组件工厂
我们把 接口 组件工厂改为实体类
为了保持可以扩展和维护
我们定义了一个 接口 工厂
interface 工厂 {
}
class 组件工厂 implements 工厂 {
public 组件 生产组件(组件注册表 ID) throws Exception {
try {
Field f = 组件注册表.class.getField(ID.toString());
组件描述 描述 = f.getAnnotation(组件描述.class);
Class 组件类 = 描述.组件类();
return (组件) 组件类.newInstance();
// 注意,组件类.newInstance();的调用的时候要确保这个组件类有个不带参数的构造函数
// 如果要使用带参数的构造函数,可以在@interface 组件描述 中增加一个成员
// 构造函数[] 构造函数参数() default{};
// @interface 构造函数 {Class[] 构造函数的参数();}
// 通过 组件类.getConstructors(); 来得到这个类的不同构造方法
// 这样就可以根据用户提供的信息用不同的构造函数实例话对象
// 带不同的构造函数,这里先不讨论,后面我会给出代码
} catch (Exception e) {
throw new Exception ("没有找到对应的组件");
}
}
}
经过上面的修改,代码如下
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
@Retention(RetentionPolicy.RUNTIME)
@interface 组件描述 {
Class 组件类();
}
enum 组件注册表 {
@组件描述(组件类 = Linux文本.class)
Linux_文本,
@组件描述(组件类 = Linux标签.class)
Linux_标签,
@组件描述(组件类 = Windows文本.class)
Windows_文本,
@组件描述(组件类 = Windows标签.class)
Windows_标签,
}
interface 组件 {}
interface 文本 extends 组件 {}
interface 标签 extends 组件 {}
class Linux文本 implements 文本{
public String toString() {
return "Linux文本";
}
}
class Linux标签 implements 标签{
public String toString() {
return "Linux标签";
}
}
class Windows文本 implements 文本{
public String toString() {
return "Windows文本";
}
}
class Windows标签 implements 标签{
public String toString() {
return "Windows标签";
}
}
interface 工厂 {}
class 组件工厂 implements 工厂{
public 组件 生产组件(组件注册表 ID) throws Exception {
try {
Field f = 组件注册表.class.getField(ID.toString());
组件描述 描述 = f.getAnnotation(组件描述.class);
Class 组件类 = 描述.组件类();
return (组件) 组件类.newInstance();
} catch (Exception e) {
throw new Exception ("没有找到对应的组件");
}
}
}
class 客户系统显示 {
private 文本 text;
private 标签 label;
public static void main(String args[]) {
客户系统显示 clientOS = new 客户系统显示();
组件工厂 factory = new 组件工厂();
try {
clientOS.text = (文本) factory.生产组件(组件注册表.Linux_文本);
clientOS.label = (标签) factory.生产组件(组件注册表.Linux_标签);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(clientOS.label);
System.out.println(clientOS.text);
}
}
这个时候我们增加一个 下拉框
需要改动的地方
1.增加一个 interface 下拉框 extends 组件 {}
2.增加2个实现类
class Windows下拉框 implements 下拉框{}
class Linux下拉框implements 下拉框{}
3.组件注册表 增加2个成员
@组件描述(组件类 = Linux下拉框.class)
Linux_下拉框,
@组件描述(组件类 = Windows下拉框.class)
Windows_下拉框,
和上面的比起来我们只需要在 组件注册表中增加2个成员,而不需要去修改
1.组件工厂
2.Linux组件工厂
3.Windows标签组件工厂
因为这里要修改3个地方,是不是觉得麻烦,反正我觉得麻烦了点
还有一点就是用户调用的时候不需要再使用factory.生产标签组件();等方法,只要一个factory.生产组件就可以了,这样符合简单工厂的模式
第三部分 带参数的构造函数代码
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
@Retention(RetentionPolicy.RUNTIME)
@interface 构造函数 {
/**
* 构造函数的参数类型
* @return
*/
Class[] 构造函数的参数();
}
@Retention(RetentionPolicy.RUNTIME)
@interface 组件描述 {
Class 组件类();
/**
* 返回组件的构造函数 <br>
* 如果长度为0,则调用没有参数的构造函数 <br>
* @return 构造函数[]
*/
构造函数[] 构造函数参数() default{};
}
enum 组件注册表 {
/**
* Linux_文本 的对应实体类为 Linux文本 <br>
* Linux的构造函数有 <br>
* 1. Linux文本(String 显示的文字) ; <br>
* 2. Linux文本(String 显示的文字, Integer 文本字体大小);
*/
@组件描述(组件类 = Linux文本.class,
构造函数参数 = {@构造函数(构造函数的参数={String.class}) ,
@构造函数(构造函数的参数={String.class, Integer.class}) } )
Linux_文本,
@组件描述(组件类 = Linux标签.class)
Linux_标签,
@组件描述(组件类 = Windows文本.class)
Windows_文本,
@组件描述(组件类 = Windows标签.class)
Windows_标签,
}
interface 组件 {}
interface 文本 extends 组件 {}
interface 标签 extends 组件 {}
class Linux文本 implements 文本{
private String text;
private Integer size;
public Linux文本(String text) {
this.text = text;
}
public Linux文本(String text, Integer size) {
this.text = text;
this.size = size;
}
public String toString() {
return "Linux文本" + (text == null ? "":",文本内容为:"+text) + (size == null ? "":",文本字体大小为:"+size);
}
}
class Linux标签 implements 标签{
public String toString() {
return "Linux标签";
}
}
class Windows文本 implements 文本{
public String toString() {
return "Windows文本";
}
}
class Windows标签 implements 标签{
public String toString() {
return "Windows标签";
}
}
interface 工厂 {}
class 组件工厂 implements 工厂{
public 组件 生产组件(组件注册表 ID, Object[] 参数) throws Exception {
try {
Field f = 组件注册表.class.getField(ID.toString());
组件描述 描述 = f.getAnnotation(组件描述.class);
Class 组件类 = 描述.组件类();
构造函数[] ano = 描述.构造函数参数();
if (参数 != null) {
for (int i = 0; i < ano.length; i++) {
构造函数 temp = ano;
Class[] 构造函数S = temp.构造函数的参数();
if (参数.length == 构造函数S.length) {
for (int j = 0; j < 参数.length; j++) {
if (参数[j].getClass().toString().equals(构造函数S[j].toString())) {
if ( j == 参数.length - 1) {
Constructor cons = 组件类.getConstructor(构造函数S);
return (组件) cons.newInstance(参数);
}
} else break;
}
}
continue;
}
throw new Exception ("没有找到对应的组件");
} else
return (组件) 组件类.newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new Exception ("没有找到对应的组件");
}
}
}
class 客户系统显示 {
private 文本 text;
private 标签 label;
public static void main(String args[]) {
客户系统显示 clientOS = new 客户系统显示();
组件工厂 factory = new 组件工厂();
try {
Object [] params = {"初始化文本", new Integer(20)};
clientOS.text = (文本) factory.生产组件(组件注册表.Linux_文本,params);
clientOS.label = (标签) factory.生产组件(组件注册表.Linux_标签,null);
System.out.println(clientOS.label);
System.out.println(clientOS.text);
Object [] params2 = {"初始化"};
clientOS.text = (文本) factory.生产组件(组件注册表.Linux_文本,params2);
System.out.println(clientOS.text);
} catch (Exception e) {
e.printStackTrace();
}
}
}
</script>