以下為java抽象工廠模式的一個(gè)例子,都是個(gè)人的一點(diǎn)想法,有什么不足的地方,懇求大家予以指出,歡迎討論
我們使用的界面上有
文本 {Linux文本,Windows文本}
標(biāo)簽 {Linux標(biāo)簽,Windows標(biāo)簽}
等等.
第一部分 抽象工廠的實(shí)現(xiàn)
interface 文本 {}
interface 標(biāo)簽 {}
class Linux文本 implements 文本{
public String toString() {
return "Linux文本";
}
}
class Linux標(biāo)簽 implements 標(biāo)簽{
public String toString() {
return "Linux標(biāo)簽";
}
}
class Windows文本 implements 文本{
public String toString() {
return "Windows文本";
}
}
class Windows標(biāo)簽 implements 標(biāo)簽{
public String toString() {
return "Windows標(biāo)簽";
}
}
interface 組件工廠 {
public 文本 生產(chǎn)文本組件();
public 標(biāo)簽 生產(chǎn)標(biāo)簽組件();
}
class Linux組件工廠 implements 組件工廠 {
public 文本 生產(chǎn)文本組件() {
return new Linux文本();
}
public 標(biāo)簽 生產(chǎn)標(biāo)簽組件() {
return new Linux標(biāo)簽();
}
}
class Windows標(biāo)簽組件工廠 implements 組件工廠 {
public 文本 生產(chǎn)文本組件() {
return new Windows文本();
}
public 標(biāo)簽 生產(chǎn)標(biāo)簽組件() {
return new Windows標(biāo)簽();
}
}
class 客戶系統(tǒng)顯示 {
private 文本 text;
private 標(biāo)簽 label;
public static void main(String args[]) {
客戶系統(tǒng)顯示 clientOS = new 客戶系統(tǒng)顯示();
組件工廠 factory = new Linux組件工廠();
clientOS.label = factory.生產(chǎn)標(biāo)簽組件();
clientOS.text = factory.生產(chǎn)文本組件();
System.out.println(clientOS.label);
System.out.println(clientOS.text);
}
}
如果按照上面的標(biāo)準(zhǔn),我們要添加一個(gè)新的組件 下拉框
A.需要修改的地方有
1.組件工廠
2.Linux組件工廠
3.Windows標(biāo)簽組件工廠
B.需要增加的有
1.interface 下拉框 {}
2.class Linux下拉框 implements 下拉框
3.class Windows下拉框 implements 下拉框
C.調(diào)用的地方也會(huì)多出一個(gè)factory.生產(chǎn)下拉框組件();
第二部分 改革抽象工廠
有沒有覺得要改動(dòng)的地方有點(diǎn)多呢,下面我們來(lái)改革一下
1.把 組件工廠中的
生產(chǎn)文本組件();
生產(chǎn)標(biāo)簽組件();
...
都改為
生產(chǎn)組件(組件標(biāo)識(shí));
這樣帶來(lái)的好處就是前面提到的,以下的修改就免去了
/**************************/
......
A.需要修改的地方有
1.組件工廠
2.Linux組件工廠
3.Windows標(biāo)簽組件工廠
......
/**************************/
要做到上面的,需要做以下幾件事情
1.增加一個(gè)Annotation來(lái)說(shuō)明后面增加的 組件注冊(cè)表
@interface 組件描述 {
Class 組件類();
}
2.增加一個(gè)Enum
enum 組件注冊(cè)表 {
/**
* Linux_文本 的對(duì)應(yīng)實(shí)體類為 Linux文本
*/
@組件描述(組件類 = Linux文本.class)
Linux_文本,
@組件描述(組件類 = Linux標(biāo)簽.class)
Linux_標(biāo)簽,
@組件描述(組件類 = Windows文本.class)
Windows_文本,
@組件描述(組件類 = Windows標(biāo)簽.class)
Windows_標(biāo)簽,
}
3.我們不再需要
interface 組件工廠,class Windows標(biāo)簽組件工廠,class Linux組件工廠
我們把 接口 組件工廠改為實(shí)體類
為了保持可以擴(kuò)展和維護(hù)
我們定義了一個(gè) 接口 工廠
interface 工廠 {
}
class 組件工廠 implements 工廠 {
public 組件 生產(chǎn)組件(組件注冊(cè)表 ID) throws Exception {
try {
Field f = 組件注冊(cè)表.class.getField(ID.toString());
組件描述 描述 = f.getAnnotation(組件描述.class);
Class 組件類 = 描述.組件類();
return (組件) 組件類.newInstance();
// 注意,組件類.newInstance();的調(diào)用的時(shí)候要確保這個(gè)組件類有個(gè)不帶參數(shù)的構(gòu)造函數(shù)
// 如果要使用帶參數(shù)的構(gòu)造函數(shù),可以在@interface 組件描述 中增加一個(gè)成員
// 構(gòu)造函數(shù)[] 構(gòu)造函數(shù)參數(shù)() default{};
// @interface 構(gòu)造函數(shù) {Class[] 構(gòu)造函數(shù)的參數(shù)();}
// 通過(guò) 組件類.getConstructors(); 來(lái)得到這個(gè)類的不同構(gòu)造方法
// 這樣就可以根據(jù)用戶提供的信息用不同的構(gòu)造函數(shù)實(shí)例話對(duì)象
// 帶不同的構(gòu)造函數(shù),這里先不討論,后面我會(huì)給出代碼
} catch (Exception e) {
throw new Exception ("沒有找到對(duì)應(yīng)的組件");
}
}
}
經(jīng)過(guò)上面的修改,代碼如下
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
@Retention(RetentionPolicy.RUNTIME)
@interface 組件描述 {
Class 組件類();
}
enum 組件注冊(cè)表 {
@組件描述(組件類 = Linux文本.class)
Linux_文本,
@組件描述(組件類 = Linux標(biāo)簽.class)
Linux_標(biāo)簽,
@組件描述(組件類 = Windows文本.class)
Windows_文本,
@組件描述(組件類 = Windows標(biāo)簽.class)
Windows_標(biāo)簽,
}
interface 組件 {}
interface 文本 extends 組件 {}
interface 標(biāo)簽 extends 組件 {}
class Linux文本 implements 文本{
public String toString() {
return "Linux文本";
}
}
class Linux標(biāo)簽 implements 標(biāo)簽{
public String toString() {
return "Linux標(biāo)簽";
}
}
class Windows文本 implements 文本{
public String toString() {
return "Windows文本";
}
}
class Windows標(biāo)簽 implements 標(biāo)簽{
public String toString() {
return "Windows標(biāo)簽";
}
}
interface 工廠 {}
class 組件工廠 implements 工廠{
public 組件 生產(chǎn)組件(組件注冊(cè)表 ID) throws Exception {
try {
Field f = 組件注冊(cè)表.class.getField(ID.toString());
組件描述 描述 = f.getAnnotation(組件描述.class);
Class 組件類 = 描述.組件類();
return (組件) 組件類.newInstance();
} catch (Exception e) {
throw new Exception ("沒有找到對(duì)應(yīng)的組件");
}
}
}
class 客戶系統(tǒng)顯示 {
private 文本 text;
private 標(biāo)簽 label;
public static void main(String args[]) {
客戶系統(tǒng)顯示 clientOS = new 客戶系統(tǒng)顯示();
組件工廠 factory = new 組件工廠();
try {
clientOS.text = (文本) factory.生產(chǎn)組件(組件注冊(cè)表.Linux_文本);
clientOS.label = (標(biāo)簽) factory.生產(chǎn)組件(組件注冊(cè)表.Linux_標(biāo)簽);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(clientOS.label);
System.out.println(clientOS.text);
}
}
這個(gè)時(shí)候我們?cè)黾右粋€(gè) 下拉框
需要改動(dòng)的地方
1.增加一個(gè) interface 下拉框 extends 組件 {}
2.增加2個(gè)實(shí)現(xiàn)類
class Windows下拉框 implements 下拉框{}
class Linux下拉框implements 下拉框{}
3.組件注冊(cè)表 增加2個(gè)成員
@組件描述(組件類 = Linux下拉框.class)
Linux_下拉框,
@組件描述(組件類 = Windows下拉框.class)
Windows_下拉框,
和上面的比起來(lái)我們只需要在 組件注冊(cè)表中增加2個(gè)成員,而不需要去修改
1.組件工廠
2.Linux組件工廠
3.Windows標(biāo)簽組件工廠
因?yàn)檫@里要修改3個(gè)地方,是不是覺得麻煩,反正我覺得麻煩了點(diǎn)
還有一點(diǎn)就是用戶調(diào)用的時(shí)候不需要再使用factory.生產(chǎn)標(biāo)簽組件();等方法,只要一個(gè)factory.生產(chǎn)組件就可以了,這樣符合簡(jiǎn)單工廠的模式
第三部分 帶參數(shù)的構(gòu)造函數(shù)代碼
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 構(gòu)造函數(shù) {
/**
* 構(gòu)造函數(shù)的參數(shù)類型
* @return
*/
Class[] 構(gòu)造函數(shù)的參數(shù)();
}
@Retention(RetentionPolicy.RUNTIME)
@interface 組件描述 {
Class 組件類();
/**
* 返回組件的構(gòu)造函數(shù) <br>
* 如果長(zhǎng)度為0,則調(diào)用沒有參數(shù)的構(gòu)造函數(shù) <br>
* @return 構(gòu)造函數(shù)[]
*/
構(gòu)造函數(shù)[] 構(gòu)造函數(shù)參數(shù)() default{};
}
enum 組件注冊(cè)表 {
/**
* Linux_文本 的對(duì)應(yīng)實(shí)體類為 Linux文本 <br>
* Linux的構(gòu)造函數(shù)有 <br>
* 1. Linux文本(String 顯示的文字) ; <br>
* 2. Linux文本(String 顯示的文字, Integer 文本字體大小);
*/
@組件描述(組件類 = Linux文本.class,
構(gòu)造函數(shù)參數(shù) = {@構(gòu)造函數(shù)(構(gòu)造函數(shù)的參數(shù)={String.class}) ,
@構(gòu)造函數(shù)(構(gòu)造函數(shù)的參數(shù)={String.class, Integer.class}) } )
Linux_文本,
@組件描述(組件類 = Linux標(biāo)簽.class)
Linux_標(biāo)簽,
@組件描述(組件類 = Windows文本.class)
Windows_文本,
@組件描述(組件類 = Windows標(biāo)簽.class)
Windows_標(biāo)簽,
}
interface 組件 {}
interface 文本 extends 組件 {}
interface 標(biāo)簽 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 ? "":",文本內(nèi)容為:"+text) + (size == null ? "":",文本字體大小為:"+size);
}
}
class Linux標(biāo)簽 implements 標(biāo)簽{
public String toString() {
return "Linux標(biāo)簽";
}
}
class Windows文本 implements 文本{
public String toString() {
return "Windows文本";
}
}
class Windows標(biāo)簽 implements 標(biāo)簽{
public String toString() {
return "Windows標(biāo)簽";
}
}
interface 工廠 {}
class 組件工廠 implements 工廠{
public 組件 生產(chǎn)組件(組件注冊(cè)表 ID, Object[] 參數(shù)) throws Exception {
try {
Field f = 組件注冊(cè)表.class.getField(ID.toString());
組件描述 描述 = f.getAnnotation(組件描述.class);
Class 組件類 = 描述.組件類();
構(gòu)造函數(shù)[] ano = 描述.構(gòu)造函數(shù)參數(shù)();
if (參數(shù) != null) {
for (int i = 0; i < ano.length; i++) {
構(gòu)造函數(shù) temp = ano;
Class[] 構(gòu)造函數(shù)S = temp.構(gòu)造函數(shù)的參數(shù)();
if (參數(shù).length == 構(gòu)造函數(shù)S.length) {
for (int j = 0; j < 參數(shù).length; j++) {
if (參數(shù)[j].getClass().toString().equals(構(gòu)造函數(shù)S[j].toString())) {
if ( j == 參數(shù).length - 1) {
Constructor cons = 組件類.getConstructor(構(gòu)造函數(shù)S);
return (組件) cons.newInstance(參數(shù));
}
} else break;
}
}
continue;
}
throw new Exception ("沒有找到對(duì)應(yīng)的組件");
} else
return (組件) 組件類.newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new Exception ("沒有找到對(duì)應(yīng)的組件");
}
}
}
class 客戶系統(tǒng)顯示 {
private 文本 text;
private 標(biāo)簽 label;
public static void main(String args[]) {
客戶系統(tǒng)顯示 clientOS = new 客戶系統(tǒng)顯示();
組件工廠 factory = new 組件工廠();
try {
Object [] params = {"初始化文本", new Integer(20)};
clientOS.text = (文本) factory.生產(chǎn)組件(組件注冊(cè)表.Linux_文本,params);
clientOS.label = (標(biāo)簽) factory.生產(chǎn)組件(組件注冊(cè)表.Linux_標(biāo)簽,null);
System.out.println(clientOS.label);
System.out.println(clientOS.text);
Object [] params2 = {"初始化"};
clientOS.text = (文本) factory.生產(chǎn)組件(組件注冊(cè)表.Linux_文本,params2);
System.out.println(clientOS.text);
} catch (Exception e) {
e.printStackTrace();
}
}
}
</script>