Java的面向?qū)ο缶幊?/a>">Java的面向?qū)ο缶幊?/a>
625
2025-04-03
1,枚舉類型
1.1,枚舉類的定義
枚舉是一種特殊類。枚舉是有固定實(shí)例個(gè)數(shù)的類型,我們可以把枚舉理解成有固定個(gè)數(shù)實(shí)例的多例模式。
定義枚舉類型其實(shí)就是在定義一個(gè)類,只不過(guò)是很多細(xì)節(jié)由編譯器幫補(bǔ)齊了,所以,某種程度上enum關(guān)鍵字的作用就像是class或者interface。
當(dāng)使用enum定義枚舉類型時(shí),實(shí)際上所定義出來(lái)的類型是繼承自java.lang.Enum類。而每個(gè)被枚舉的成員其實(shí)就是定義的枚舉類型的一個(gè)實(shí)例,它們都被默認(rèn)為final。無(wú)法改變常數(shù)名稱所設(shè)定的值,它們也是public和static的成員,這與接口中的常量限制相同。可以通過(guò)類名稱直接使用它們。
1.2,枚舉類的結(jié)構(gòu)
1.2.1,枚舉類的結(jié)構(gòu)(1)
枚舉像普通的類一樣可以添加屬性和方法,可以為它添加靜態(tài)和非靜態(tài)的屬性或方法。
enum SeasonEnum { //注意:枚舉寫在最前面,否則編譯出錯(cuò)。 SPRING, SUMMER, AUTUMN, WINTERS; private final static String position = "first"; public static SeasonEnum getSeason(String s) { if (position.equals(s)) { return SPRING; } else { return AUTUMN; } } }
1.2.2,枚舉類的結(jié)構(gòu)(2)
設(shè)計(jì)帶構(gòu)造器的枚舉
enum Gender { //通過(guò)括號(hào)賦值,而且必須帶有一個(gè)參構(gòu)造器和一個(gè)屬性跟方法,否則編譯出錯(cuò)。 //賦值必須都賦值或都不賦值,不能一部分賦值一部分不賦值。 //如果不賦值則不能寫構(gòu)造器,賦值編譯也出錯(cuò)。 MAN("MAN"), WOMEN("WOMEN"); private final String value; //構(gòu)造器默認(rèn)也只能是private,從而保證構(gòu)造函數(shù)只能在內(nèi)部使用。 Gender(String value) { this.value = value; } public String getValue() { return value; } }
1.2.3,枚舉類的結(jié)構(gòu)(3)
設(shè)計(jì)帶抽象方法的枚舉
enum OrderState { CANCEL {public String getName(){return "已取消";}}, WAITCONFIRM{public String getName(){return "待審核";}}, WAITPAYMENT{public String getName(){return "等待付款";}}; public abstract String getName(); //此枚舉類的抽象方法 }
1.3,枚舉的應(yīng)用
枚舉是一種類型,用于定義常量,以限制變量的賦值;賦值時(shí)通過(guò)"枚舉名.值"取得枚舉中的值。
枚舉類的常用API如下:
2,包裝類
2.1,包裝類定義
包裝類(1)
雖然Java是面向?qū)ο蟮木幊陶Z(yǔ)言,但它所包含的8種基本數(shù)據(jù)類型卻不支持面向?qū)ο蟮木幊虣C(jī)制(沒(méi)有屬性和方法)。
在Java中,很多類和方法都需要接收引用類型的對(duì)象,此時(shí)就無(wú)法將一個(gè)基本數(shù)據(jù)類型的值傳入。
為了解決這樣的問(wèn)題,JDK中提供了一系列的包裝類,通過(guò)這些包裝類可以將基本數(shù)據(jù)類型的值包裝為引用數(shù)據(jù)類型的對(duì)象。
包裝類(2)
包裝類的繼承關(guān)系
[img1]
包裝類(3)
2.2,自動(dòng)裝箱和拆箱
自動(dòng)裝箱:是指將基本數(shù)據(jù)類型的變量賦給對(duì)應(yīng)的包裝類變量。
自動(dòng)拆箱:是指將包裝類對(duì)象類型直接賦給一個(gè)對(duì)應(yīng)的基本數(shù)據(jù)類型變量。
public class Test { public static void main(String[] args) { int i = 10; Integer integer = i;//將基本數(shù)據(jù)類型的變量賦值給相應(yīng)的包裝類變量,這就是自動(dòng)裝箱,把基本數(shù)據(jù)類型變成了引用類型。 Integer a = 5; int x = a;//將包裝類的變量賦給相應(yīng)的基本數(shù)據(jù)類型變量,這就是自動(dòng)拆箱。 System.out.println(integer);//10 System.out.println(x);//5 } }
包裝類API(1)
1,通過(guò)引用數(shù)據(jù)類型字符串String類的valueOf()方法可以將8種基本數(shù)據(jù)類型轉(zhuǎn)換為相應(yīng)的字符串類型。
2,通過(guò)8種包裝類型的靜態(tài)方法valueOf()既可以將對(duì)應(yīng)的基本數(shù)據(jù)類型轉(zhuǎn)換為包裝類,也可以將變量?jī)?nèi)容匹配的字符串轉(zhuǎn)換為對(duì)應(yīng)的包裝類(Character包裝類除外)。
3,通過(guò)8種包裝類的有參數(shù)構(gòu)造方法同樣既可以將對(duì)應(yīng)的基本數(shù)據(jù)類型轉(zhuǎn)換為包裝類,也可以將變量?jī)?nèi)容匹配的字符串轉(zhuǎn)換為對(duì)應(yīng)的包裝類(Character包裝類除外)。
4,通過(guò)8種包裝類型的靜態(tài)方法parseXXX()可以將變量?jī)?nèi)容匹配的字符串轉(zhuǎn)換為對(duì)應(yīng)的基本數(shù)據(jù)類型。
5,包裝類都重寫了Object類中的toString()方法,以字符串的形式返回被包裝的基本數(shù)據(jù)類型的值。
public class Test { public static void main(String[] args) { //1,通過(guò)引用數(shù)據(jù)類型字符串String類的valueOf()方法可以將8種基本數(shù)據(jù)類型轉(zhuǎn)換為相應(yīng)的字符串類型。 // long a = 66; // float d = 3.14f; // char c = '華'; // boolean bool = true; // // String string1 = String.valueOf(a);//將正數(shù)轉(zhuǎn)換為String // System.out.println(string1);//66 //2,通過(guò)8種包裝類型的靜態(tài)方法valueOf()既可以將對(duì)應(yīng)的基本數(shù)據(jù)類型轉(zhuǎn)換為包裝類,也可以將變量?jī)?nèi)容匹配的字符串轉(zhuǎn)換為對(duì)應(yīng)的包裝類(Character包裝類除外)。 // Integer integer=Integer.valueOf("華為Integer");//編譯通過(guò),運(yùn)行時(shí)異常(Exception in thread "main" java.lang.NumberFormatException: For input string: "華為Integer") // Float f = Float.valueOf("華為Float"); // Boolean b = Boolean.valueOf("true"); //3,通過(guò)8種包裝類的有參數(shù)構(gòu)造方法同樣既可以將對(duì)應(yīng)的基本數(shù)據(jù)類型轉(zhuǎn)換為包裝類,也可以將變量?jī)?nèi)容匹配的字符串轉(zhuǎn)換為對(duì)應(yīng)的包裝類(Character包裝類除外)。 // Integer integer = new Integer("華為");//編譯通過(guò),運(yùn)行時(shí)異常(Exception in thread "main" java.lang.NumberFormatException: For input string: "華為") //4,通過(guò)8種包裝類型的靜態(tài)方法parseXXX()可以將變量?jī)?nèi)容匹配的字符串轉(zhuǎn)換為對(duì)應(yīng)的基本數(shù)據(jù)類型。 // int i = Integer.parseInt("123華為");//將字符串轉(zhuǎn)換為基本數(shù)據(jù)類型 //5,包裝類都重寫了Object類中的toString()方法,以字符串的形式返回被包裝的基本數(shù)據(jù)類型的值。 // Boolean b = Boolean.valueOf("true"); // System.out.println(b); //true } }
包裝類API(2)
除了Character外,包裝類都有valueOf(String s)方法,可以根據(jù)String類型的參數(shù)創(chuàng)建包裝類對(duì)象,但參數(shù)字符串s不能為null,而且字符串必須是可以解析為相應(yīng)基本類型的數(shù)據(jù),否則雖然編譯通過(guò),但運(yùn)行時(shí)會(huì)報(bào)錯(cuò)。
public class Test { public static void main(String[] args) { Integer i1 = Integer.valueOf("123"); System.out.println(i1);//123 Integer i2 = Integer.valueOf("12a"); System.out.println(i2);//報(bào)錯(cuò),Exception in thread "main" java.lang.NumberFormatException: For input string: "12a" } }
包裝類API(3)
除了Character外,包裝類都有parseXXX(String s)的靜態(tài)方法,將字符串轉(zhuǎn)換為對(duì)應(yīng)的基本類型的數(shù)據(jù)。參數(shù)s不能為null,而且同樣必須是可以解析為相應(yīng)基本類型的數(shù)據(jù),否則雖然編譯通過(guò),但運(yùn)行時(shí)會(huì)報(bào)錯(cuò)。
public class Test { public static void main(String[] args) { int i = Integer.parseInt("123"); System.out.println(i);//123 Integer integer = Integer.parseInt("huawei"); System.out.println(integer);//Exception in thread "main" java.lang.NumberFormatException: For input string: "huawei" } }
3,設(shè)計(jì)模式
設(shè)計(jì)模式(Design Pattern)代表了最佳的實(shí)踐,通常被有經(jīng)驗(yàn)的面向?qū)ο蟮能浖_(kāi)發(fā)人員所采用。
設(shè)計(jì)模式是軟件開(kāi)發(fā)人員在軟件開(kāi)發(fā)過(guò)程中面臨的一般問(wèn)題的解決方案。這些解決方案是眾多軟件開(kāi)發(fā)人員經(jīng)過(guò)相當(dāng)長(zhǎng)的一段時(shí)間的試驗(yàn)和錯(cuò)誤總結(jié)出來(lái)的。
什么GOF(Gang of Four)?
在1994年,由Erich Gamma,Richard Helm,Ralph Johnson和John Vlissides四人合著出版了一本名為Design Patterns - Elements of Reusable
Object-Oriented Software(中文譯名:設(shè)計(jì)模式 - 可復(fù)用的面向?qū)ο筌浖兀┑臅摃状翁岬搅塑浖_(kāi)發(fā)中設(shè)計(jì)模式的概念。
對(duì)接口編程而不是對(duì)實(shí)現(xiàn)編程。
優(yōu)先使用對(duì)象組合而不是繼承。
設(shè)計(jì)模式的類型
根據(jù)設(shè)計(jì)模式的參考書 Design Patterns - Elements of Reusable Object-Oriented Software(中文譯名:設(shè)計(jì)模式 - 可復(fù)用的面向?qū)ο筌浖兀┲兴岬降模偣灿?3種設(shè)計(jì)模式。
這些模式可以分為三大類:創(chuàng)建型模式(Creating Patterns),結(jié)構(gòu)型模式(Structural Patterns),行為型模式(Behavioral Patterns)。
3.1,單例模式
單例模式(1)
單例模式(Singleton Pattern)是Java中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類提供了一種訪問(wèn)其唯一的對(duì)象的方式,可以直接訪問(wèn),不需要實(shí)例化該類的對(duì)象。
1,單例類只能有一個(gè)實(shí)例
2,單例類必須自己創(chuàng)建自己的唯一實(shí)例
3,單例類必須給其他對(duì)象提供這一實(shí)例
單例模式(2)
創(chuàng)建一個(gè)SingleObject類。SingleObject類有它的私有構(gòu)造函數(shù)和本身的一個(gè)靜態(tài)實(shí)例。
SingleObject類提供了一個(gè)靜態(tài)方法,供外界獲取它的靜態(tài)實(shí)例。SingletonPatternDemo類使用SingleObject類來(lái)獲取SingleObject對(duì)象。
[img2]
單例模式(3)
方式一:懶漢式,線程安全
是否Lazy初始化:是
是否多線程安全:是
實(shí)現(xiàn)難度:易
描述:這種方式具備很好的lazy loading,能夠在多線程中很好的工作,但是,效率很低,99%情況下不需要同步。
class Singleton { //1,單例類只能有一個(gè)實(shí)例 //2,單例類必須自己創(chuàng)建自己的唯一實(shí)例 //3,單例類必須給所有其他對(duì)象提供這一實(shí)例 private static Singleton singleton;//確保整個(gè)類只有一份 private Singleton()//將構(gòu)造私有化,這樣就不能在外部通過(guò)new+構(gòu)造方法再來(lái)創(chuàng)建Singleton對(duì)象了 { } public static synchronized Singleton getInstance()//確保是線程安全的 { if (singleton == null) { singleton = new Singleton(); } return singleton; } } public class TestSingleton { public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); Singleton s3 = Singleton.getInstance(); System.out.println(s1 == s2);//true System.out.println(s2 == s3);//true } }
單例模式(4)
優(yōu)點(diǎn):第一次調(diào)用才初始化,避免內(nèi)存浪費(fèi)。
缺點(diǎn):必須加鎖synchronized才能保證單例,但加鎖會(huì)影響效率。不過(guò)getInstance()的性能對(duì)應(yīng)用程序不是很關(guān)鍵(該方法使用不太頻繁)。
public class Singleton { private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
單例模式(5)
方式二:餓漢式
是否lazy初始化:否
是否多線程安全:是
實(shí)現(xiàn)難度:易
描述:這種方式比較常用,但容易產(chǎn)生垃圾對(duì)象
public class Singleton2 { private static Singleton2 singleton2 = new Singleton2(); private Singleton2() { } public static Singleton2 getInstance() { return singleton2; } }
單例模式(6)
優(yōu)點(diǎn):沒(méi)有加鎖,執(zhí)行效率會(huì)提高。
缺點(diǎn):類加載時(shí)就初始化,浪費(fèi)內(nèi)存。
它基于classloader機(jī)制避免了多線程的同步問(wèn)題,不過(guò),instance在類裝載時(shí)就實(shí)例化,雖然導(dǎo)致類裝載的原因很多種,在單例模式中大多數(shù)都是調(diào)用了getInstance方法,但是也不能確定有其他的方式(或者其他的靜態(tài)方法)導(dǎo)致類裝載,這時(shí)候初始化instance顯然沒(méi)有達(dá)到lazy
loading的效果。
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
3.2,策略模式
策略模式(1)
在策略模式(Strategy Pattern)中,一個(gè)類的行為或其算法可以在運(yùn)行時(shí)更改。這種類型的設(shè)計(jì)模式屬于行為型模式。
意圖:定義一系列的算法,把它們一個(gè)個(gè)封裝起來(lái),并且使它們可相互替換。
主要解決:在有多種算法相似的情況下,使用if…else所帶來(lái)的復(fù)雜度和難以維護(hù)。
何時(shí)使用:一個(gè)系統(tǒng)有許多類,而區(qū)分它們的只是它們直接的行為。
如何解決:將這些算法封裝成一個(gè)個(gè)類,任意替換。
關(guān)鍵代碼:實(shí)現(xiàn)同一個(gè)接口。
1,諸葛亮的錦囊妙計(jì),每一個(gè)錦囊就是一個(gè)策略。
2,旅行的出行方式,選擇騎自行車、坐汽車,每一種旅行方式就是一個(gè)策略。
3,Java AWT中的LayoutManage。
策略模式(2)
創(chuàng)建一個(gè)定義活動(dòng)的Strategy接口和實(shí)現(xiàn)了Strategy接口的實(shí)體策略類。Context是一個(gè)使用了某種策略的類。
StrategyPatternDemo,我們的演示類使用Context和策略對(duì)象來(lái)演示Context在它所配置或使用的策略改變時(shí)的行為變化。
[img3]
public interface Strategy { public int doOperation(int num1, int num2); }
public class OperationAdd implements Strategy { @Override public int doOperation(int num1, int num2) { return num1 + num2; } }
public class OperationSubtract implements Strategy { @Override public int doOperation(int num1, int num2) { return num1 - num2; } }
public class OperationMultiply implements Strategy { @Override public int doOperation(int num1, int num2) { return num1 * num2; } }
public class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public int executeStrategy(int num1, int num2) { return strategy.doOperation(num1, num2); } }
public class StrategyPatternDemo { public static void main(String[] args) { //使用Context來(lái)查看當(dāng)它改變策略Strategy時(shí)的行為變化 Context context = new Context(new OperationAdd()); System.out.println("1+2=" + context.executeStrategy(1, 2));//1+2=3 Context context1 = new Context(new OperationSubtract()); System.out.println("1-2=" + context1.executeStrategy(1, 2));//1-2=-1 Context context2 = new Context(new OperationMultiply()); System.out.println("1*2=" + context2.executeStrategy(1, 2));//1*2=2 } }
策略模式(3)
優(yōu)點(diǎn):1,算法可以自由切換。2,避免使用多重條件判斷。3,拓展性良好。
缺點(diǎn):1,策略類會(huì)增多。2,所有策略類都需要對(duì)外暴露。
1,如果在一個(gè)系統(tǒng)里面有許多類,它們之間的區(qū)別僅在于它們的行為,那么使用策略模式可以動(dòng)態(tài)地讓一個(gè)對(duì)象在許多行為中選擇一種行為。
2,一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種。
3,如果一個(gè)對(duì)象有很多地行為,如果不用恰當(dāng)?shù)哪J剑@些行為就只好使用多重的條件選擇語(yǔ)句來(lái)實(shí)現(xiàn)。
3.3,工廠模式
工廠模式(1)
工廠模式(Factory Pattern)是Java中最常用的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
在工廠模式中,我們?cè)趧?chuàng)建對(duì)象時(shí)不會(huì)對(duì)客戶端暴露創(chuàng)建邏輯,并且是通過(guò)使用一個(gè)共同的接口來(lái)指向新創(chuàng)建的對(duì)象。
工廠模式(2)
意圖:定義一個(gè)創(chuàng)建對(duì)象的接口,讓其子類自己決定實(shí)例化哪一個(gè)工廠類,工廠模式使其創(chuàng)建過(guò)程延遲到子類進(jìn)行。
主要解決:主要解決接口選擇的問(wèn)題。
何時(shí)使用:我們明確地計(jì)劃不同條件下創(chuàng)建不同實(shí)例時(shí)。
如何解決:讓其子類實(shí)現(xiàn)工廠接口,返回的也是一個(gè)抽象的產(chǎn)品。
關(guān)鍵代碼:創(chuàng)建過(guò)程在其子類執(zhí)行。
1,你需要一輛汽車,可以直接從工廠里面拿貨,而不用去管汽車是怎么做出來(lái)的,以及這個(gè)汽車?yán)锩娴木唧w實(shí)現(xiàn)。
2,Hibernate換數(shù)據(jù)庫(kù)只需要換方言和驅(qū)動(dòng)即可。
工廠模式(3)
創(chuàng)建一個(gè)Shape接口和實(shí)現(xiàn)Shape接口的實(shí)體類。下一步是定義工廠類ShapeFactory。
FactoryPatternDemo類使用ShapeFactory來(lái)獲取Shape對(duì)象。它將向ShapeFactory傳遞信息(Circle/Rectangle/Square),以便獲取它所需對(duì)象的類型。
[img4]
public interface Shape { void draw(); }
//圓形 public class Circle implements Shape { @Override public void draw() { System.out.println("畫圓形 Inside Circle::draw() method."); } }
//正方形 public class Square implements Shape { @Override public void draw() { System.out.println("畫正方形 Inside Square::draw() method."); } }
//矩形 public class Rectangle implements Shape { @Override public void draw() { System.out.println("畫長(zhǎng)方形 Inside Rectangle::draw() method."); } }
public class ShapeFactory { //在簡(jiǎn)單工廠模式中用于被創(chuàng)建實(shí)例的方法通常為靜態(tài)(static)方法 //因此簡(jiǎn)單工廠模式又被稱為靜態(tài)工廠方法(Static Factory Method) public static Shape getShape(String shapeType) { if (shapeType == null) { return null; } if (shapeType.equalsIgnoreCase("CIRCLE")) { return new Circle(); } else if (shapeType.equalsIgnoreCase("RECTANGLE")) { return new Rectangle(); } else if (shapeType.equalsIgnoreCase("SQUARE")) { return new Square(); } return null; } }
public class FactoryPatternDemo { public static void main(String[] args) { System.out.println("----------Circle----------"); //獲取Circle的對(duì)象,并調(diào)用它的 draw 方法 Shape circleShape = ShapeFactory.getShape("circle"); //調(diào)用Circle的draw方法 circleShape.draw();//畫圓形 Inside Circle::draw() method. System.out.println("----------Rectangle----------"); //獲取Rectangle的對(duì)象,并調(diào)用它的 draw 方法 Shape rectangleShape = ShapeFactory.getShape("rectangle"); //調(diào)用Rectangle的draw方法 rectangleShape.draw();//畫長(zhǎng)方形 Inside Rectangle::draw() method. System.out.println("----------Square----------"); //獲取Square的對(duì)象,并調(diào)用它的 draw 方法 Shape squareShape = ShapeFactory.getShape("square"); //調(diào)用Square的draw方法 squareShape.draw();//畫正方形 Inside Square::draw() method. } }
工廠模式(4)
優(yōu)點(diǎn):1,一個(gè)調(diào)用者想創(chuàng)建一個(gè)對(duì)象,只要知道其名稱就可以了。2,拓展性高,如果想增加一個(gè)產(chǎn)品,只要擴(kuò)展一個(gè)工廠類就可以。3,屏蔽產(chǎn)品的具體實(shí)現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口。
缺點(diǎn):每次增加一個(gè)產(chǎn)品時(shí),都需要增加一個(gè)具體類和對(duì)象實(shí)現(xiàn)工廠,使得系統(tǒng)中類的個(gè)數(shù)成倍增長(zhǎng),在一定程度上增加了系統(tǒng)的復(fù)雜度,同時(shí)增加系統(tǒng)具體類的依賴。這并不是什么好事。
1,日志記錄器:記錄可能記錄到本地硬盤、系統(tǒng)事件、遠(yuǎn)程服務(wù)器等,用戶可以選擇記錄日志到什么地方。
2,數(shù)據(jù)庫(kù)訪問(wèn),當(dāng)用戶不知道最后系統(tǒng)采用哪一種數(shù)據(jù)庫(kù),以及數(shù)據(jù)庫(kù)可能有變化時(shí)。
3,設(shè)計(jì)一個(gè)連接服務(wù)器的框架,需要三個(gè)協(xié)議,“POP3”,“IMAP”,“HTTP”,可以把這三個(gè)作為產(chǎn)品類,同時(shí)實(shí)現(xiàn)一個(gè)接口。
工廠模式(5)
作為一個(gè)創(chuàng)建類模式,在任何需要生成復(fù)雜對(duì)象的地方,都可以使用工廠方法模式。
有一點(diǎn)需要注意的是復(fù)雜對(duì)象適合使用工廠模式,而簡(jiǎn)單對(duì)象,特別是只需要通過(guò)new就可以完成創(chuàng)建的對(duì)象,無(wú)需使用工廠模式。
如果使用工廠模式,就需要引入一個(gè)工廠類,會(huì)增加系統(tǒng)復(fù)雜度。
3.4,代理模式
代理模式(1)
在代理模式(Proxy Pattern)中,一個(gè)類代表另一個(gè)類的功能。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式。
在代理模式中,我們創(chuàng)建擁有現(xiàn)有對(duì)象的對(duì)象,以便向外界提供功能接口。
代理模式(2)
意圖:為其他對(duì)象提供一種代理以控制這個(gè)對(duì)象的訪問(wèn)。
主要解決:在直接訪問(wèn)對(duì)象時(shí)帶來(lái)的問(wèn)題,比如說(shuō):要訪問(wèn)的對(duì)象在遠(yuǎn)程的機(jī)器上。
面向?qū)ο笙到y(tǒng)中,有些對(duì)象由于某些原因(比如對(duì)象創(chuàng)建開(kāi)銷很大,或者某些操作需要安全控制,或者需要進(jìn)程外的訪問(wèn)),直接訪問(wèn)會(huì)給使用者或者系統(tǒng)結(jié)構(gòu)帶來(lái)麻煩,我們可以在訪問(wèn)此對(duì)象時(shí)加上一個(gè)對(duì)此對(duì)象的訪問(wèn)層。
何時(shí)使用:想在訪問(wèn)一個(gè)類時(shí)做一些控制。
如何解決:增加中間層。
關(guān)鍵代碼:實(shí)現(xiàn)與被代理類組合。
1,買火車票不一定在火車站買,也可以去代售點(diǎn)。
2,一張支票或銀行存單是賬戶中資金的代理。支票在市場(chǎng)交易中用來(lái)代替現(xiàn)金,并提供對(duì)簽發(fā)人賬號(hào)上資金的控制。
3,Spring中的AOP。
代理模式(3)
我們將創(chuàng)建一個(gè)Image接口和實(shí)現(xiàn)了Image接口的實(shí)體類。ProxyImage是一個(gè)代理類,減少RealImage對(duì)象加載的內(nèi)存占用。
ProxyPatternDemo類使用ProxyImage來(lái)獲取要加載的Image對(duì)象,并按照需求進(jìn)行顯示。
[img5]
public interface Image { void display(); }
public class RealImage implements Image { private String fileName; public RealImage(String fileName) { this.fileName = fileName; loadPromDisk(fileName); } @Override public void display() { System.out.println("Displaying " + fileName); } private void loadPromDisk(String fileName) { System.out.println("Loading " + fileName); } }
public class ProxyImage implements Image { private RealImage realImage;//代理類中擁有要被代理的對(duì)象 private String fileName; public ProxyImage(String fileName) { this.fileName = fileName; } @Override public void display() { if (realImage == null) { realImage = new RealImage(fileName); } realImage.display(); } }
public class ProxyPatternDemo { public static void main(String[] args) { Image image = new ProxyImage("uml_proxy.jpg");//創(chuàng)建代理對(duì)象 //第一次調(diào)用,圖片從磁盤加載 image.display(); System.out.println("------------------"); image.display(); /* * 輸出結(jié)果 * Loading uml_proxy.jpg Displaying uml_proxy.jpg ------------------ Displaying uml_proxy.jpg * */ } }
代理模式(4)
優(yōu)點(diǎn):1,職責(zé)清晰。2,高擴(kuò)展性。3,智能化。
缺點(diǎn):1,由于在客戶端和真實(shí)真題之間增加了代理對(duì)象,因此有些類型的代理模式可能會(huì)造成請(qǐng)求的處理速度變慢。2,實(shí)現(xiàn)代理模式需要額外的工作,有些代理模式的實(shí)現(xiàn)非常復(fù)雜。
按職責(zé)來(lái)劃分,通常有以下使用場(chǎng)景:1,遠(yuǎn)程代理。2,虛擬代理。3,Copy-on-Write代理。4,保護(hù)(Protect or
Access)代理。5,Cache代理。6,防火墻(Firewall)代理。7,同步化(Synchronization)代理。8,智能引用(Smart Reference)代理。
3.5,門面模式
門面模式(1)
現(xiàn)代軟件系統(tǒng)都比較復(fù)雜,設(shè)計(jì)師處理復(fù)雜系統(tǒng)的一個(gè)常見(jiàn)方法便是分而治之,一個(gè)系統(tǒng)劃分成好幾個(gè)小的子系統(tǒng)。
如果醫(yī)院作為一個(gè)子系統(tǒng),按照部門職能,這個(gè)系統(tǒng)可以劃分為掛號(hào)、門診、劃價(jià)、化驗(yàn)、收費(fèi)、取藥等。
首先病人必須先掛號(hào),然后門診。如果醫(yī)生要求化驗(yàn),病人必須首先劃價(jià),然后繳費(fèi),才可以到化驗(yàn)部門做化驗(yàn),化驗(yàn)后再回到門診室。
看病的病人要與這些部門打交道,就如同一個(gè)子系統(tǒng)的客戶端與一個(gè)子系統(tǒng)的各個(gè)類打交道一樣,不是一件容易的事情。
[img6]
門面模式(2)
解決這種不便的方法便是引入門面模式,醫(yī)院可以設(shè)置一個(gè)接待員的位置,由接待員負(fù)責(zé)代為掛號(hào)、劃價(jià)、繳費(fèi)、取藥等。
這個(gè)接待員就是門面模式的體現(xiàn),病人只接觸接待員,由接待員與各個(gè)部門打交道。
[img7]
門面模式(3)
門面模式也叫外觀模式(Facade Pattern)
這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它向現(xiàn)有的系統(tǒng)添加一個(gè)可以訪問(wèn)系統(tǒng)的接口,來(lái)隱藏系統(tǒng)的復(fù)雜性。
這種模式涉及到一個(gè)單一的類,該類提供了客戶端請(qǐng)求的簡(jiǎn)化方法和對(duì)現(xiàn)有系統(tǒng)類方法的委托調(diào)用。
門面模式(4)
我們將創(chuàng)建一個(gè)Shape接口和實(shí)現(xiàn)了Shape接口的實(shí)體類。下一步是定義一個(gè)外觀類ShapeMaker。
ShapeMaker類使用實(shí)體類來(lái)代表用戶對(duì)這些類的調(diào)用。FacadePatternDemo類使用ShapeMaker類來(lái)顯示結(jié)果。
[img8]
public interface Shape//抽象接口,放公共代碼和定義規(guī)范的 { void draw(); }
public class Rectangle implements Shape { @Override public void draw() { System.out.println("畫矩形 Inside Rectangle::draw() method."); } }
public class Circle implements Shape { @Override public void draw() { System.out.println("畫圓形 Inside Circle::draw() method."); } }
public class Square implements Shape { @Override public void draw() { System.out.println("畫正方形 Inside Square::draw() method."); } }
//外觀類 -> 門面 public class ShapeMaker { private Shape circle; private Shape rectangle; private Shape square; public ShapeMaker() { circle = new Circle(); rectangle = new Rectangle(); square = new Square(); } public void drawCircle() { circle.draw(); } public void drawRectangle() { rectangle.draw(); } public void drawSquare() { square.draw(); } }
public class FacadePatternDemo { public static void main(String[] args) { ShapeMaker shapeMaker = new ShapeMaker(); shapeMaker.drawCircle(); shapeMaker.drawCircle(); shapeMaker.drawSquare(); /* * 輸出結(jié)果: 畫圓形 Inside Circle::draw() method. 畫圓形 Inside Circle::draw() method. 畫正方形 Inside Square::draw() method. * */ } }
Java
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。