java設(shè)計模式--三種工廠模式詳解
簡單工廠
簡單工廠模式是屬于創(chuàng)建型模式,是工廠模式的一種。簡單工廠模式是由一個工廠對象決定創(chuàng)建出哪一種產(chǎn)品類的實例。定義了一個創(chuàng)建對象的類,由這個類來封裝實例化對象的行為(代碼)。當(dāng)我們會用到大量的創(chuàng)建某種、某類或者某批對象時,就會使用到工廠模式。
由于創(chuàng)建實例的方法通常為靜態(tài)(static)方法,因此簡單工廠模式又被成為靜態(tài)工廠方法模式(Static Factory Method)。

- Product表示產(chǎn)品接口,也可用抽象類實現(xiàn),封裝產(chǎn)品間共有的屬性。
- ConcreteProduct*表示具體的實際產(chǎn)品。
- Factory表示工廠,工廠根據(jù)需要來創(chuàng)建相應(yīng)的產(chǎn)品。
這樣一來,當(dāng)添加新的產(chǎn)品C時,只需要修改工廠部分代碼即可,而傳統(tǒng)方法需要在每一個創(chuàng)建產(chǎn)品的地方都進(jìn)行修改??梢岳斫鉃榘丫唧w的產(chǎn)品創(chuàng)建封裝成一個工廠類。
舉個例子,大富翁的地圖創(chuàng)建:
- AbstractBlock是接口,表示抽象的地塊,包括方法printBlock()打印地塊。
- Empty、Prison、Park實現(xiàn)上述接口,表示空地(*)、監(jiān)獄(&)和公園(#)。
- SimpleFactory是創(chuàng)建地塊的簡單工廠。
類圖:

代碼:
1.產(chǎn)品接口
public interface AbstractBlock {
public void printBlock();
}
2.產(chǎn)品接口實現(xiàn)子類
public class Empty implements AbstractBlock{
@Override
public void printBlock() {
System.out.print("* ");
}
}
public class Park implements AbstractBlock{
@Override
public void printBlock() {
System.out.print("# ");
}
}
public class Prison implements AbstractBlock{
@Override
public void printBlock() {
System.out.print("& ");
}
}
3.簡單工廠類
public class SimpleFactory {
public AbstractBlock getBlock(String type){ //根據(jù)傳參創(chuàng)建不同的地塊
if(type.equalsIgnoreCase("Empty")){
return new Empty();
} else if(type.equalsIgnoreCase("Park")){
return new Park();
} else if(type.equalsIgnoreCase("Prison")){
return new Prison();
}
return null;
}
}
4.調(diào)用工廠
public class Map {
public void getMap(){
SimpleFactory simpleFactory=new SimpleFactory(); //實例化工廠
ArrayList<AbstractBlock> map=new ArrayList<AbstractBlock>(); //地塊集合
String []types=new String[3];
types[0]="Empty";
types[1]="park";
types[2]="Prison";
Random rd = new Random();
for(int i=1;i<=12;i++){ //隨機(jī)用工廠創(chuàng)建地塊并放入集合
int tt = rd.nextInt(types.length);
map.add(simpleFactory.getBlock(types[tt]));
}
//地圖大小寫死了,不是重點
for(int i=0;i<12;i++){
map.get(i).printBlock();
if(i==3||i==5||i==7)
System.out.println();
if(i==4||i==6)
System.out.print(" ");
}
}
}
5.測試
public class MonoPoly {
public static void main(String[] args) {
Map map=new Map();
map.getMap();
}
}
運行結(jié)果

工廠方法
不難發(fā)現(xiàn),當(dāng)增加新的產(chǎn)品時需要對簡單工廠類修改,或創(chuàng)建多個簡單工廠。(比如增加一個法院地塊)工廠方法進(jìn)一步解耦合,把工廠類抽象,不再負(fù)責(zé)所有實例的創(chuàng)建,而是把具體的創(chuàng)建工作交給了子類去完成,實例化延遲到子類加載,由子類來決定要實例化的類。

抽象化工廠類,把具體實例化工作交給其子類實現(xiàn)。
代碼:
1.工廠接口
public interface AbstractFactory {
public AbstractBlock createBlock();
}
2.工廠實現(xiàn)子類
public class EmptyFactory implements AbstractFactory {
@Override
public AbstractBlock createBlock() {
return new Empty();
}
}
public class ParkFactory implements AbstractFactory {
@Override
public AbstractBlock createBlock() {
return new Park();
}
}
public class PrisonFactory implements AbstractFactory {
@Override
public AbstractBlock createBlock() {
return new Prison();
}
}
3.產(chǎn)品接口
public interface AbstractBlock {
public void printBlock();
}
4.產(chǎn)品實現(xiàn)子類
public class Empty implements AbstractBlock {
@Override
public void printBlock() {
System.out.print("* ");
}
}
public class Park implements AbstractBlock {
@Override
public void printBlock() {
System.out.print("# ");
}
}
public class Prison implements AbstractBlock {
@Override
public void printBlock() {
System.out.print("& ");
}
}
5.調(diào)用
public class Map {
public void getMap() {
ArrayList<AbstractBlock> map=new ArrayList<AbstractBlock>(); //地塊集合
AbstractFactory abstractFactory;
Random rd = new Random();
for(int i=1;i<=12;i++){ //隨機(jī)用工廠創(chuàng)建地塊并放入集合
int tt = rd.nextInt(3);
if(tt==0)abstractFactory=new EmptyFactory();
else if(tt==1)abstractFactory=new ParkFactory();
else abstractFactory=new PrisonFactory();
map.add(abstractFactory.createBlock());
}
//地圖大小寫死了,不是重點
for(int i=0;i<12;i++){
map.get(i).printBlock();
if(i==3||i==5||i==7)
System.out.println();
if(i==4||i==6)
System.out.print(" ");
}
}
}
6.測試
public class MonoPoly {
public static void main(String[] args) {
Map map=new Map();
map.getMap();
}
}
運行結(jié)果:

抽象工廠
不難發(fā)現(xiàn)當(dāng)創(chuàng)建新的產(chǎn)品接口時,也需要對工廠方法修改,或創(chuàng)建多個工廠方法。(比如增加魔法地塊簇,對應(yīng)組產(chǎn)品魔法公園、魔法空地、魔法監(jiān)獄等)
抽象工廠將工廠方法進(jìn)一步抽象。定義了一個接口用于創(chuàng)建相關(guān)或有依賴關(guān)系的對象簇,而無需指明具體的類??梢愿鶕?jù)創(chuàng)建對象類型使用對應(yīng)的工廠子類。這樣將單個的簡單工廠類變成了工廠簇,更利于代碼的維護(hù)和擴(kuò)展。

把工廠類抽象后,對應(yīng)不同子類工廠(普通/魔法),生產(chǎn)對應(yīng)的一組產(chǎn)品。最后調(diào)用時統(tǒng)一調(diào)用抽象接口即可,不必知道具體對象,面向接口編程。
1.產(chǎn)品接口
public interface AbstractBlock {
void printBlock();
}
2.產(chǎn)品抽象子類-普通產(chǎn)品
public abstract class NormalAbstractBlock implements AbstractBlock {
public abstract void printBlock();
}
2.2普通空地
public class NormalEmpty extends NormalAbstractBlock {
public void printBlock() {
System.out.print("* ");
}
}
2.3普通公園
public class NormalPark extends NormalAbstractBlock {
public void printBlock() {
System.out.print("# ");
}
}
2.4普通監(jiān)獄
public class NormalPrison extends NormalAbstractBlock {
public void printBlock() {
System.out.print("& ");
}
}
3.1產(chǎn)品抽象子類-魔法產(chǎn)品
public abstract class MagicAbstractBlock implements AbstractBlock {
public abstract void printBlock();
}
3.2魔法空地
public class MagicEmpty extends MagicAbstractBlock {
public void printBlock() {
System.out.print("e ");
}
}
3.3魔法公園
public class MagicPark extends MagicAbstractBlock {
public void printBlock() {
System.out.print("g ");
}
}
3.4魔法監(jiān)獄
public class MagicPrison extends MagicAbstractBlock {
public void printBlock() {
System.out.print("p ");
}
}
4.工廠接口
public interface AbstractFactory {
AbstractBlock getEmpty();
AbstractBlock getPrison();
AbstractBlock getPark();
}
5.工廠實現(xiàn)子類-普通工廠
public class NormalFactory implements AbstractFactory {
public AbstractBlock getEmpty() { return new NormalEmpty(); }
public AbstractBlock getPrison() { return new NormalPrison(); }
public AbstractBlock getPark() { return new NormalPark(); }
}
6.工廠實現(xiàn)子類-魔法工廠
public class MagicFactory implements AbstractFactory {
public AbstractBlock getEmpty() { return new MagicEmpty(); }
public AbstractBlock getPrison() {return new MagicPrison(); }
public AbstractBlock getPark() { return new MagicPark(); }
}
7.調(diào)用
public class Map {
public void getMap(AbstractFactory af){
ArrayList<AbstractBlock> map=new ArrayList<AbstractBlock>();
map.add(af.getEmpty());
map.add(af.getPrison());
map.add(af.getPark());
Random rd = new Random(3);
int col=12;
for(int i=1;i<=col;i++){
int tt = rd.nextInt(3);
map.get(tt).printBlock();
if(i==4||i==6||i==8)
System.out.println();
if(i==5||i==7)
System.out.print(" ");
}
}
}
8.測試
public class Monopoly {
public void play(){
Map map=new Map();
Scanner scan = new Scanner(System.in);
System.out.println("請輸入指令(1輸出普通地圖,2輸出魔法地圖)");
int order;
order = scan.nextInt();
if(order == 1){
map.getMap(new NormalFactory());
}else{
map.getMap(new MagicFactory());
}
}
}
運行結(jié)果:


總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
java面試常見問題---ConcurrentHashMap
ConcurrentHashMap是由Segment數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成。Segment的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu),今天給大家普及java面試常見問題---ConcurrentHashMap知識,一起看看吧2021-06-06
springboot+thymeleaf找不到視圖的解決方案
這篇文章主要介紹了springboot+thymeleaf找不到視圖的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
Java傳值調(diào)用和傳引用調(diào)用方式(參數(shù)引用為null問題)
這篇文章主要介紹了Java傳值調(diào)用和傳引用調(diào)用方式(參數(shù)引用為null問題),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09

