一蛙卤、適配器模式
下面來看看適配器的三個角色:
- Tagret目標角色:
該角色定義把其他類轉(zhuǎn)換為何種接口拂蝎,也就是我們所期望接口可缚。 - Adaptee源角色:
你想把誰轉(zhuǎn)換成目標角色霎迫,它使已經(jīng)存在的、運行良好的類或?qū)ο蟪强矗?jīng)過適配器角色包裝女气,成為一個嶄新的角色。 - Adapter適配器模式:
適配器模式的核心角色测柠,其他兩個角色都是已經(jīng)存在的角色炼鞠,而適配器角色是需要新建立的,它的職責(zé)非常簡單:把源角色轉(zhuǎn)換為目標角色轰胁。
通用代碼實現(xiàn)
目標角色
public interface Target {
//目標角色自有的方法
public void request();
}
public class ConcreteTarget implements Target {
public void request (){
}
}
目標角色是一個已經(jīng)正式運行的角色谒主,不可能去修改角色中的方法。
源角色
public class Adaptee {
//原有的業(yè)務(wù)邏輯
public void doSomething(){
}
}
適配器角色
public class Adapter extends Adaptee implements Target {
public void reqest(){
super.doSmothing();
}
}
二赃阀、橋接模式
橋接模式將繼承模式轉(zhuǎn)化成關(guān)聯(lián)關(guān)系霎肯,他降低了類與類之間的耦合度,減少了系統(tǒng)中類的數(shù)量榛斯,也減少了代碼量观游。
橋接是一個接口,它與一方應(yīng)該是綁定的驮俗,也就是解耦的雙方中的一方必然是繼承這個接口的懂缕,這一方就是實現(xiàn)方,而另一方正是要與這一方解耦的抽象方王凑,如果不采用橋接模式搪柑,一般我們的處理方式是直接使用繼承來實現(xiàn),這樣雙方之間處于強鏈接索烹,類之間關(guān)聯(lián)性極強工碾,如要進行擴展,必然導(dǎo)致類結(jié)構(gòu)急劇膨脹百姓。
三渊额、組合模式
組合模式,就是在一個對象中包含其他對象瓣戚,這些被包含的對象可能是終點對象(不再包含別的對象)端圈,也有可能是非終點對象(其內(nèi)部還包含其他對象,或叫組對象)子库,我們將對象稱為節(jié)點舱权,即一個根節(jié)點包含許多子節(jié)點,這些子節(jié)點有的不再包含子節(jié)點仑嗅,而有的仍然包含子節(jié)點宴倍,以此類推
Component抽象構(gòu)件角色
定義參加組合對象的共有方法和屬性张症,可以定義一些默認的行為或?qū)傩浴?/p>Leaf葉子構(gòu)件
葉子對象,其下再也沒有其他的分支鸵贬,也就是遍歷的最小單位俗他。Composite樹枝構(gòu)件
樹枝對象,它的作用是組合樹枝節(jié)點和葉子節(jié)點形成一個樹形結(jié)構(gòu)阔逼。
public abstract class Component {
//個體和整體都具有的共享
public void doSomething(){
//編寫業(yè)務(wù)邏輯
}
}
/**
*樹枝構(gòu)件
*/
public class Composite extends Component {
//構(gòu)件容器
private ArrayList<Component> componentArrayList = new ArrayList<Component>();
//增加一個葉子構(gòu)件或樹枝構(gòu)件
public void add(Component component){
this.componentArrayList.add(component);
}
//刪除一個葉子構(gòu)件或樹枝構(gòu)件
public void remove(Component component){
this.componentArrayList.remove(component);
}
//獲得分支下的所有葉子構(gòu)件和樹枝構(gòu)件
public ArrayList<Component> getChildren(){
return this.componentArrayList;
}
}
//樹葉節(jié)點是沒有子下級對象的對象兆衅,定義參加組合的原始對象行為,其通用源代碼
public class Leaf extends Component {
/*
* 可以覆寫父類方法
* public void doSomething(){
*
* }
*/
}
四嗜浮、裝飾器模式
裝飾模式通用類圖如下所示:
在類圖中羡亩,有四個角色需要說明:
Component抽象構(gòu)件
Component是一個接口或者是抽象類,就是定義我們最核心的對象危融,也就是最原始的對象畏铆。ConcreteComponent 具體構(gòu)件
ConcreteComponent是最核心、最原始吉殃、最基本的接口或抽象類的實現(xiàn)辞居,你要裝飾的就是它。Decorator裝飾角色
一般是一個抽象類蛋勺,做什么用呢瓦灶?實現(xiàn)接口或者抽象方法,它里面可不一定有抽象的方法抱完,在它的屬性里必然有一個private變量指向Component抽象構(gòu)件倚搬。具體裝飾角色
ConcreteDecoratorA和ConcreteDecoratorB是兩個具體的裝飾類,你要把你最核心的乾蛤、最原始的、最基本的東西裝飾成其他東西
//抽象構(gòu)件
public abstract class Component {
//抽象的方法
public abstract void operate();
}
//具體構(gòu)件
public class ConcreteComponent extends Component {
//具體實現(xiàn)
@Override
public void operate() {
System.out.println("do Something");
}
}
//抽象裝飾者
public abstract class Decorator extends Component {
private Component component = null;
//通過構(gòu)造函數(shù)傳遞被修飾者
public Decorator(Component _component){
this.component = _component;
}
//委托給被修飾者執(zhí)行
@Override
public void operate() {
this.component.operate();
}
}
//具體的裝飾類
public class ConcreteDecorator1 extends Decorator {
//定義被修飾者
public ConcreteDecorator1(Component _component){
super(_component);
}
//定義自己的修飾方法
private void method1(){
System.out.println("method1 修飾");
}
//重寫父類的Operation方法
public void operate(){
this.method1();
super.operate();
}
}
public class ConcreteDecorator2 extends Decorator {
//定義被修飾者
public ConcreteDecorator2(Component _component){
super(_component);
}
//定義自己的修飾方法
private void method1(){
System.out.println("method1 修飾");
}
//重寫父類的Operation方法
public void operate(){
this.method1();
super.operate();
}
}
五捅僵、外觀模式
也就是提供一個訪問子系統(tǒng)的接口家卖,除了這個接口不允許有任何訪問子系統(tǒng)的行為發(fā)生,其通用類圖如下:
Facade門面角色
客戶端可以調(diào)用這個角色的方法庙楚。此角色知曉子系統(tǒng)的所有功能和責(zé)任上荡。一般情況下,本角色會將所有從客戶端發(fā)來的請求委派到相應(yīng)的子系統(tǒng)去馒闷,也就說該角色沒有實際的業(yè)務(wù)邏輯酪捡,只是一個委托類。subsystem子系統(tǒng)角色
可以同時有一個或者多個子系統(tǒng)纳账。每一個子系統(tǒng)都不是一個單獨的類逛薇,而是一個類的集合。子系統(tǒng)并不知道門面的存在疏虫。對于子系統(tǒng)而言永罚,門面僅僅是另外一個客戶端而已啤呼。
// 子系統(tǒng)
public class ClassA {
public void doSomethingA(){
//業(yè)務(wù)邏輯
}
}
public class ClassB {
public void doSomethingB(){
//業(yè)務(wù)邏輯
}
}
public class ClassC {
public void doSomethingC(){
//業(yè)務(wù)邏輯
}
}
//門面對象
public class Facade {
//被委托的對象
private ClassA a = new ClassA();
private ClassB b = new ClassB();
private ClassC c = new ClassC();
//提供給外部訪問的方法
public void methodA(){
this.a.doSomethingA();
}
public void methodB(){
this.b.doSomethingB();
}
public void methodC(){
this.c.doSomethingC();
}
}
六、享元模式
要求細粒度對象呢袱,那么不可避免地使得對象數(shù)量多且性質(zhì)相近官扣,那我們就將這些對象的信息分為兩個部分:內(nèi)部狀態(tài)(intrinsic)與外部狀態(tài)(extrinsic)。
● 內(nèi)部狀態(tài)
內(nèi)部狀態(tài)是對象可共享出來的信息羞福,存儲在享元對象內(nèi)部并且不會隨環(huán)境改變而改變惕蹄,如id、name等治专,它們可以作為一個對象的動態(tài)附加信息卖陵,不必直接儲存在具體某個對象中,屬于可以共享的部分看靠。
● 外部狀態(tài)
外部狀態(tài)是對象得以依賴的一個標記赶促,是隨環(huán)境改變而改變的、不可以共享的狀態(tài)
Flyweight——抽象享元角色
它簡單地說就是一個產(chǎn)品的抽象類挟炬,同時定義出對象的外部狀態(tài)和內(nèi)部狀態(tài)的接口或?qū)崿F(xiàn)鸥滨。ConcreteFlyweight——具體享元角色
具體的一個產(chǎn)品類,實現(xiàn)抽象角色定義的業(yè)務(wù)谤祖。該角色中需要注意的是內(nèi)部狀態(tài)處理應(yīng)該與環(huán)境無關(guān)婿滓,不應(yīng)該出現(xiàn)一個操作改變了內(nèi)部狀態(tài),同時修改了外部狀態(tài)粥喜,這是絕對不允許的凸主。unsharedConcreteFlyweight——不可共享的享元角色
不存在外部狀態(tài)或者安全要求(如線程安全)不能夠使用共享技術(shù)的對象,該對象一般不會出現(xiàn)在享元工廠中额湘。FlyweightFactory——享元工廠
職責(zé)非常簡單卿吐,就是構(gòu)造一個池容器,同時提供從池中獲得對象的方法锋华。
//抽象享元角色
public abstract class Flyweight {
//內(nèi)部狀態(tài)
private String intrinsic;
//外部狀態(tài)
protected final String Extrinsic;
//要求享元角色必須接受外部狀態(tài)
public Flyweight(String _Extrinsic){
this.Extrinsic = _Extrinsic;
}
//定義業(yè)務(wù)操作
public abstract void operate();
//內(nèi)部狀態(tài)的getter/setter
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
//具體享元角色嗡官。實現(xiàn)自己的業(yè)務(wù)邏輯,然后接收外部狀態(tài)毯焕,以便內(nèi)部業(yè)務(wù)邏輯對外部狀態(tài)的依賴衍腥。
//注意,我們在抽象享元中對外部狀態(tài)加上了final關(guān)鍵字纳猫,
//防止意外產(chǎn)生婆咸,什么意外?獲得了一個外部狀態(tài)芜辕,然后無意修改了一下尚骄,池就混亂了
public class ConcreteFlyweight1 extends Flyweight{
//接受外部狀態(tài)
public ConcreteFlyweight1(String _Extrinsic){
super(_Extrinsic);
}
//根據(jù)外部狀態(tài)進行邏輯處理
public void operate(){
//業(yè)務(wù)邏輯
}
}
public class ConcreteFlyweight2 extends Flyweight{
//接受外部狀態(tài)
public ConcreteFlyweight2(String _Extrinsic){
super(_Extrinsic);
}
//根據(jù)外部狀態(tài)進行邏輯處理
public void operate(){
//業(yè)務(wù)邏輯
}
}
//享元工廠
public class FlyweightFactory {
//定義一個池容器
private static HashMap<String,Flyweight> pool= new HashMap<String,Flyweight>();
//享元工廠
public static Flyweight getFlyweight(String Extrinsic){
//需要返回的對象
Flyweight flyweight = null;
//在池中沒有該對象
if(pool.containsKey(Extrinsic)){
flyweight = pool.get(Extrinsic);
}else{
//根據(jù)外部狀態(tài)創(chuàng)建享元對象
flyweight = new ConcreteFlyweight1(Extrinsic);
//放置到池中
pool.put(Extrinsic, flyweight);
}
return flyweight;
}
}
七、代理模式
代理模式通用類圖:
Subject抽象主題角色
抽象主題類可以是抽象類也可以是接口物遇,是一個最普通的業(yè)務(wù)類型定義乖仇,無特殊要求憾儒。RealSubject具體主題角色
也叫做被委托角色、被代理角色乃沙。它才是冤大頭起趾,是業(yè)務(wù)邏輯的具體執(zhí)行者。Proxy代理主題角色
也叫做委托類警儒、代理類训裆。它負責(zé)對真實角色的應(yīng)用,把所有抽象主題類定義的方法限制委托給真實主題角色實現(xiàn)蜀铲,并且在真實主題角色處理完畢前后做預(yù)處理和善后處理工作边琉。
//抽象主題類
public interface Subject {
//定義一個方法
public void request();
}
//真實主題類
public class RealSubject implements Subject {
//實現(xiàn)方法
public void request() {
//業(yè)務(wù)邏輯處理
}
}
//代理類
public class Proxy implements Subject {
//要代理哪個實現(xiàn)類
private Subject subject = null;
//默認被代理者
public Proxy(){
this.subject = new Proxy();
}
//通過構(gòu)造函數(shù)傳遞代理者
public Proxy(Object...objects ){
}
//實現(xiàn)接口中定義的方法
public void request() {
this.before();
this.subject.request();
this.after();
}
//預(yù)處理
private void before(){
//do something
}
//善后處理
private void after(){
//do something
}
}
JDK 自帶的動態(tài)代理:
java.lang.reflect.Proxy:生成動態(tài)代理類和對象;
java.lang.reflect.InvocationHandler(處理器接口):可以通過invoke方法實現(xiàn)
對真實角色的代理訪問记劝。
每次通過 Proxy 生成的代理類對象都要指定對應(yīng)的處理器對象变姨。
- 接口:Subject.java
public interface Subject {
public String speak();
}
- 真實對象:RealSubject.java
public class RealSubject implements Subject{
@Override
public String speak() {
System.out.println("speak");
return "speak";
}
}
- 處理器對象:MyInvocationHandler.java
public class MyInvocationHandler implements InvocationHandler {
/**
* 因為需要處理真實角色,所以要把真實角色傳進來
*/
Subject realSubject ;
public MyInvocationHandler(Subject realSubject) {
this.realSubject = realSubject;
}
/**
*
* @param proxy 代理類
* @param method 正在調(diào)用的方法
* @param args 方法的參數(shù)
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("調(diào)用代理類");
if(method.getName().equals("speak")){
String str = (String)method.invoke(realSubject, args);
System.out.println("調(diào)用的是說話的方法");
return str ;
}
}
}
- 調(diào)用端:Main.java
public static void main(String[] args) {
//真實對象
Subject realSubject = new RealSubject();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(realSubject);
//代理對象
Subject proxyClass = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Subject.class}, myInvocationHandler);
proxyClass.speak();
}