1. 程式人生 > >【JAVA設計模式】外觀模式(Facade Pattern)

【JAVA設計模式】外觀模式(Facade Pattern)

簡單 產生 creat ide oid dsm ref 功能 .net

一 定義

為子系統中的一組接口提供一個一致的界面。Facade模式定義了一個高層的接口,這個接口使得這一子系統更加easy使用。


二 案例

一個子系統中擁有3個模塊。每一個模塊中都有3個方法。當中一個為client調用方法,其它兩個則為各子模塊間互相調用方法。此時有例如以下需求,client為完畢功能。須要組合3個模塊中的方法才幹實現功能。

三 未使用模式情況

/**
 * @Description A模塊
 * @author jerry 
 * @date 2016年4月11日下午2:16:04
 */
public interface AModuleApi {
	public void a1();	//此方法主要用於外部調用
	public void a2();	//下面雙方法主要用於子系統內部間調用
	public void a3();
}
/**
 * @Description A模塊實現
 * @author jerry 
 * @date 2016年4月11日下午2:17:10
 */
public class AModuleImpl implements AModuleApi {

	@Override
	public void a1() {
		System.out.println("調用了A模塊");
	}

	@Override
	public void a2() {
		//TODO 主要用於子模塊間互相調用
	}

	@Override
	public void a3() {
		//TODO 主要用於子模塊間互相調用
	}
}
/**
 * @Description B模塊
 * @author jerry 
 * @date 2016年4月11日下午2:16:12
 */
public interface BModuleApi {
	public void b1();	//此方法主要用於外部調用
	public void b2();	//下面雙方法主要用於子系統內部間調用
	public void b3();
}
/**
 * @Description B模塊實現
 * @author jerry 
 * @date 2016年4月11日下午2:17:10
 */
public class BModuleImpl implements BModuleApi {

	@Override
	public void b1() {
		System.out.println("調用了B模塊");
	}

	@Override
	public void b2() {
		//TODO 主要用於子模塊間互相調用
	}

	@Override
	public void b3() {
		//TODO 主要用於子模塊間互相調用
	}
}
同理。C模塊也是如此,篇幅原因。這裏不貼代碼了,須要代碼能夠從我github下clone,文末會給出地址。 client調用例如以下:
public class Client {

	public static void main(String[] args) {
		AModuleApi a = new AModuleImpl();
		a.a1();
		BModuleApi b = new BModuleImpl();
		b.b1();
		CModuleApi c = new CModuleImpl();
		c.c1();
	}
}
相信非常easy能夠寫出這種代碼。

細致想想能夠發現,假設這樣寫。會存在例如以下問題:

  1. 代碼耦合度太高,client與子系統中各模塊都有關聯。一旦子系統有什麽更改,會涉及到client的改動。
  2. 對client學習成本太高。client須要學習各個模塊中每一個public方法。知道其什麽含義後才幹進行調用。


四 使用模式的情況

我們能夠在系統這端(即外觀模式屬於系統這端,若屬於客戶這端。仍然須要客戶去了解每一個模塊每一個方法意義,這樣無不論什麽意義。) 加入一個外觀類,由外觀類重組須要調用的方法,例如以下所看到的:
/**
 * @Description 外觀類,通常設計成單例
 * @author jerry 
 * @date 2016年4月11日下午2:43:26
 */
public class Facade {
	private Facade(){}
	
	public static void test(){
		AModuleApi a = new AModuleImpl();
		a.a1();
		BModuleApi b = new BModuleImpl();
		b.b1();
		CModuleApi c = new CModuleImpl();
		c.c1();
	}
}
public class Client {

	public static void main(String[] args) {
//		AModuleApi a = new AModuleImpl();
//		a.a1();
//		BModuleApi b = new BModuleImpl();
//		b.b1();
//		CModuleApi c = new CModuleImpl();
//		c.c1();
		
		Facade.test();
	}
}
這樣一來。client僅僅要與外觀類打交道就可以,從而更好地實現了client和子系統各模塊的耦合性。

使用外觀的目的: 不是給子系統加入新的功能接口,而是讓外部降低對子系統內部多個模塊的直接交互。松散耦合,從而可以讓外部更簡單地使用子系統。

當然有時你會有這種需求,client可能僅僅須要調用兩個模塊就可以,那麽現有的外觀模式就無法使用了,僅僅好繞開外觀類。直接找各模塊進行調用。此外,你是否發現。我的ABC模塊裏面除了有供外部調用的方法外。還有各模塊間互相調用的方法,這些方法本不須要client了解。暴露了過多內部細節。會讓client產生疑惑,這就是“接口汙染 。要解決問題,我們能夠將Facade類定義為接口,並對事實上現,使用工廠模式對其創建實例,例如以下所看到的:

public interface FacadeApi {
	public void a1();
	public void b1();
	public void c1();
	
	/**
	 * @Description 原有方法,將各模塊方法組合調用
	 * @return void
	 * @throws 
	 */
	public void test();
}
/**
 * @Description 外觀接口實現
 * @author jerry 
 * @date 2016年4月11日下午3:19:25
 */
public class FacadeImpl implements FacadeApi {

	@Override
	public void a1() {
		new AModuleImpl().a1();
	}

	@Override
	public void b1() {
		new BModuleImpl().b1();
	}

	@Override
	public void c1() {
		new CModuleImpl().c1();
	}

	@Override
	public void test() {
		a1();
		b1();
		c1();
	}
}
/**
 * @Description 外觀接口實現
 * @author jerry 
 * @date 2016年4月11日下午3:19:25
 */
public class FacadeImpl implements FacadeApi {

	@Override
	public void a1() {
		new AModuleImpl().a1();
	}

	@Override
	public void b1() {
		new BModuleImpl().b1();
	}

	@Override
	public void c1() {
		new CModuleImpl().c1();
	}

	@Override
	public void test() {
		a1();
		b1();
		c1();
	}
}
public class Client {

	public static void main(String[] args) {
//		AModuleApi a = new AModuleImpl();
//		a.a1();
//		BModuleApi b = new BModuleImpl();
//		b.b1();
//		CModuleApi c = new CModuleImpl();
//		c.c1();
		
//		Facade.test();
		
		FacadeApi api = Factory.createFacade();
		api.test();
	}
}
這樣以後,就對client降低了模塊內部方法的暴露。

五 總結

外觀模式的本質:封裝交互。簡化調用 何時使用外觀模式:
  1. 假設你希望為一個復雜的子系統提供一個簡單接口
  2. 假設構建多層結構的系統。能夠考慮使用外觀模式,使用外觀對象作為每層的入口,這樣能夠簡化層間調用,能夠減少耦合度。
------------------------------------------------------------------------------------------------------------------------------------------ Github: https://github.com/jerry-sc/designPattern
Reference:《研磨設計模式》

【JAVA設計模式】外觀模式(Facade Pattern)