以下為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>