摘要:首當(dāng)其沖的便是接口中的每個(gè)聲明必須是即便不指定也是,并且不能設(shè)置為非,詳細(xì)規(guī)則可參考可見性部分介紹。函數(shù)式接口有著不同的場景,并被認(rèn)為是對編程語言的一種強(qiáng)大的擴(kuò)展。抽象類與中的接口有些類似,與中支持默認(rèn)方法的接口更為相像。
原文鏈接:http://www.javacodegeeks.com/2015/09/how-to-design-classes-and-interfaces.html
本文是Java進(jìn)階課程的第三篇。
本課程的目標(biāo)是幫你更有效的使用Java。其中討論了一些高級主題,包括對象的創(chuàng)建、并發(fā)、序列化、反射以及其他高級特性。本課程將為你的精通Java的旅程提供幫助。
內(nèi)容綱要引言
接口
標(biāo)記性接口
函數(shù)式接口,默認(rèn)方法及靜態(tài)方法
抽象類
不可變類
匿名類
可見性
繼承
多重繼承
繼承與組合
封裝
Final類和方法
源碼下載
下章概要
引言不管使用哪種編程語言(Java也不例外),遵循好的設(shè)計(jì)原則是你編寫干凈、易讀、易測試代碼的關(guān)鍵,并且在程序的整個(gè)生命周期中,可提高后期的可維護(hù)性。在本章中,我們將從Java語言提供的基礎(chǔ)構(gòu)造模塊開始,并引入一組有助于你設(shè)計(jì)出優(yōu)秀結(jié)構(gòu)的設(shè)計(jì)原則。
具體包括:接口和接口的默認(rèn)方法(Java 8新特性),抽象類、final類和不可變類,繼承和組合以及在對象的創(chuàng)建與銷毀中介紹過的可見性(訪問控制)規(guī)則。
接口在面向?qū)ο缶幊讨校涌跇?gòu)成了基于契約的開發(fā)過程的基礎(chǔ)組件。簡而言之,接口定義了一組方法(契約),每個(gè)支持該接口的具體類都必須提供這些方法的實(shí)現(xiàn)。這是開發(fā)過程中一種簡單卻強(qiáng)有力的理念。
很多編程語言有一種或多種接口實(shí)現(xiàn)形式,而Java語言則提供了語言級的支持。下面簡單看一下Java中的接口定義形式:
package com.javacodegeeks.advanced.design; public interface SimpleInterface { void performAction(); }
在上面的代碼片段中,命名為SimpleInterface的接口只定義了一個(gè)方法performAction。接口與類的主要區(qū)別就在于接口定義了約定(聲明方法),但不為他們提供具體實(shí)現(xiàn)。
在Java中,接口的用法非常豐富:可以嵌套包含其他接口、類、枚舉和注解(枚舉和注解將在枚舉和注解的使用中介紹)以及常量,如下:
package com.javacodegeeks.advanced.design; public interface InterfaceWithDefinitions { String CONSTANT = "CONSTANT"; enum InnerEnum { E1, E2; } class InnerClass { } interface InnerInterface { void performInnerAction(); } void performAction(); }
針對上面的復(fù)雜場景,Java編譯器強(qiáng)制為嵌套的類對象構(gòu)造和方法聲明提供了一組隱式的要求。首當(dāng)其沖的便是接口中的每個(gè)聲明必須是public(即便不指定也是public,并且不能設(shè)置為非public,詳細(xì)規(guī)則可參考可見性部分介紹)。所以下面代碼中的用法與上面看到的聲明是等價(jià)的:
public void performAction(); void performAction();
另外,接口中定義的每個(gè)方法都被默認(rèn)聲明為abstract的,所以下面的聲明都是等價(jià)的:
public abstract void performAction(); public void performAction(); void performAction();
對于常量字段,除了隱式的public外,也被加上了static和final修飾,所以下面的聲明也是等價(jià)的:
String CONSTANT = "CONSTANT"; public static final String CONSTANT = "CONSTANT";
對于嵌套的類、接口或枚舉的定義,也隱式的聲明為static的,所以下面的聲明也是等價(jià)的:
class InnerClass { } static class InnerClass { }
根據(jù)個(gè)人偏好可以使用任意的聲明風(fēng)格,不過了解上面的約定倒是可以減少一些不必要的代碼編寫。
標(biāo)記性接口標(biāo)記性接口是接口的一種特殊形式:即沒有任何方法或其他嵌套定義。在使用Object的通用方法章節(jié)中我們已經(jīng)見過這種接口:Cloneable,下面是它的定義:
public interface Cloneable { }
標(biāo)記性接口并不像普通接口聲明一些契約,但卻為類“附加”或"綁定"特定的特性提供了支持。例如對于Cloneable,實(shí)現(xiàn)了此接口的類就會(huì)被認(rèn)為具有克隆的能力,盡管如何克隆并未在Cloneable中定義。另外一個(gè)廣泛使用的標(biāo)記性接口是Serializable:
public interface Serializable { }
這個(gè)接口聲明類可以被序列化或反序列化,同樣它并未指定序列化過程中使用的方法。
盡管標(biāo)記性接口并不滿足接口作為契約的主要用途,不過在面向?qū)ο笤O(shè)計(jì)過程種仍然有一定的用武之地。
函數(shù)式接口,默認(rèn)方法及靜態(tài)方法伴隨著Java 8的發(fā)布,接口被賦予了新的能力:靜態(tài)方法、默認(rèn)方法以及從lambda表達(dá)式的自動(dòng)轉(zhuǎn)換(函數(shù)式接口)。
在上面的接口部分,我們強(qiáng)調(diào)過在Java中接口只能作為聲明但不能提供任何實(shí)現(xiàn)。但默認(rèn)方法打破了這一原則:在接口中可以為default標(biāo)記的方法提供實(shí)現(xiàn),如下:
package com.javacodegeeks.advanced.design; public interface InterfaceWithDefaultMethods { void performAction(); default void performDefaulAction() { // Implementation here } }
從對象實(shí)例層次看,默認(rèn)方法可被任何的接口實(shí)現(xiàn)者重載;除此之外,接口還提供了另外的靜態(tài)方法,如下:
package com.javacodegeeks.advanced.design; public interface InterfaceWithDefaultMethods { static void createAction() { // Implementation here } }
也許你會(huì)認(rèn)為在接口中提供實(shí)現(xiàn)違背了基于契約的開發(fā)過程,不也你也可以列出很多Java把這些特性引入其中的理由。不管是帶來了幫助還是困擾,它們已然存在,你也可以使用它們。
函數(shù)式接口有著不同的場景,并被認(rèn)為是對編程語言的一種強(qiáng)大的擴(kuò)展。本質(zhì)上,函數(shù)式接口也是接口,不過包含一個(gè)抽象的方法聲明。Java 標(biāo)準(zhǔn)庫中的Runnable接口就是這種理念的絕佳范例:
@FunctionalInterface public interface Runnable { void run(); }
Java 編譯器在處理函數(shù)式接口時(shí)有所不同,并能把lamdba表達(dá)式轉(zhuǎn)化為函數(shù)式接口的實(shí)現(xiàn)。我們先看一下下面方法的定義:
public void runMe( final Runnable r ) { r.run(); }
在Java 7及以前的版本中,必須要提供Runnable接口的具體實(shí)現(xiàn)(例如使用匿名類),但在Java 8中卻可以通過傳遞lambda表達(dá)式來運(yùn)行run()方法:
runMe( () -> System.out.println( "Run!" ) );
最后,可以使用@FunctionalInterfact注解(注解會(huì)在枚舉和注解的使用章節(jié)進(jìn)行詳細(xì)介紹)告知編譯器以在編譯階段驗(yàn)證函數(shù)式接口中僅包含了一個(gè)抽象方法聲明,從而保證未來任何變更的引入不會(huì)破壞該接口的函數(shù)式特性。
抽象類抽象類是Java 語言支持的另外一個(gè)有趣的主題。抽象類與Java 7中的接口有些類似,與Java 8中支持默認(rèn)方法的接口更為相像。不同于普通類,抽象類不能實(shí)例化,但可以被繼承。更重要的是,抽象類能包含抽象方法:一種沒有定義實(shí)現(xiàn)的特殊方法,類似于接口中的方法聲明,如下:
package com.javacodegeeks.advanced.design; public abstract class SimpleAbstractClass { public void performAction() { // Implementation here } public abstract void performAnotherAction(); }
在上述例子中,SimpleAbstractClass類被聲明為abstract,并且包含了一個(gè)abstract方法。當(dāng)類有部分實(shí)現(xiàn)可被子類共享時(shí),抽象類就變得特別有用,因?yàn)樗€為子類對抽象方法的定制實(shí)現(xiàn)提供了支持入口。
另外,抽象類與接口還有一點(diǎn)不同在于接口只能提供public的聲明,而抽象類可使用所有的訪問控制規(guī)則來支持方法的可見性。
不可變類不可變性在現(xiàn)代軟件開發(fā)中的地位日益顯著。隨著多核系統(tǒng)的發(fā)展,隨之而來引入了大量并發(fā)與數(shù)據(jù)共享的問題(并發(fā)最佳實(shí)踐中會(huì)詳細(xì)介紹并發(fā)相關(guān)主題)。但有一個(gè)理念是明確的:系統(tǒng)的可變狀態(tài)越少(甚至不可變),擴(kuò)展性和可維護(hù)性就越高。
遺憾的是,Java并未從語言特性上提供強(qiáng)大的不可變性支持。盡管如此,使用一些開發(fā)技巧依然能設(shè)計(jì)出不可變的類和系統(tǒng)。首先要保證類的所有字段均設(shè)置為final,當(dāng)然這只是一個(gè)好的開始,你并不能單純的通過final就完全保證不可變性:
package com.javacodegeeks.advanced.design; import java.util.Collection; public class ImmutableClass { private final long id; private final String[] arrayOfStrings; private final Collection< String > collectionOfString; }
其次,遵循良好的初始化規(guī)則:如果字段聲明的是集合或數(shù)組,不要直接通過構(gòu)造方法的參數(shù)進(jìn)行賦值,而是使用數(shù)據(jù)復(fù)制,從而保證集合或數(shù)組的狀態(tài)不受外界的變化而改變:
public ImmutableClass( final long id, final String[] arrayOfStrings, final Collection< String > collectionOfString) { this.id = id; this.arrayOfStrings = Arrays.copyOf( arrayOfStrings, arrayOfStrings.length ); this.collectionOfString = new ArrayList<>( collectionOfString ); }
最后,提供合適的數(shù)據(jù)獲取手段(getters)。對于集合數(shù)據(jù), 應(yīng)該使用Collections.unmodifiableXxx獲取集合的不可變視圖:
public CollectiongetCollectionOfString() { return Collections.unmodifiableCollection( collectionOfString ); }
對于數(shù)組,唯一能保證不可變性的方式只有逐一復(fù)制數(shù)組中的元素到新數(shù)組而不是直接返回原數(shù)組的引用。不過有些時(shí)候這種做法可能不切實(shí)際,因?yàn)檫^大的數(shù)組復(fù)制將會(huì)為增加垃圾回收的開銷。
public String[] getArrayOfStrings() { return Arrays.copyOf( arrayOfStrings, arrayOfStrings.length ); }
盡管上面的例子提供了一些示范,然而不可變性依然不是Java中的一等公民。當(dāng)不可變類的字段引用了其他類的實(shí)例時(shí),情況可能會(huì)變得更加復(fù)雜。其他類也應(yīng)該保證不可變,然而并沒有簡單有效的途徑進(jìn)行保證。
有一些優(yōu)秀的Java源碼分析工具,像FindBugs 和 PMD能幫助你分析代碼并找出常見的Java代碼編寫缺陷。對于任何一個(gè)程序員,這些工具都應(yīng)當(dāng)成為你的好幫手。
匿名類在Java 8之前,匿名類是實(shí)現(xiàn)在類定義的地方一并完成實(shí)例化的唯一方式。匿名類的目的是減少不必要的格式代碼,并以簡捷的方式把類表示為表達(dá)式。下面看下Java中典型的創(chuàng)建線程的方式:
package com.javacodegeeks.advanced.design; public class AnonymousClass { public static void main( String[] args ) { new Thread( // Example of creating anonymous class which implements // Runnable interface new Runnable() { @Override public void run() { // Implementation here } } ).start(); } }
在上例中,需要Runnable接口的地方使用了匿名類的實(shí)例。盡管使用匿名類時(shí)有一些限制,然而其最大的缺點(diǎn)在于Java 語法強(qiáng)加給的煩雜語法。即便實(shí)現(xiàn)一個(gè)最簡單的匿名類,每次也都需要至少5行代碼來完成:
new Runnable() { @Override public void run() { } }
好在 Java 8中的lambda表達(dá)式和函數(shù)式接口消除了這些語法上的固有代碼,使得Java代碼可以變的更酷:
package com.javacodegeeks.advanced.design; public class AnonymousClass { public static void main( String[] args ) { new Thread( () -> { /* Implementation here */ } ).start(); } }可見性
我們在對象的創(chuàng)建與銷毀章節(jié)中已經(jīng)學(xué)習(xí)過Java中的可見性與可訪問性的概念,本部分我們回過頭看看父類中定義的訪問修飾符在子類里的可見性:
修飾符 | 包可見性 | 子類可見性 | 公開可見性 |
---|---|---|---|
public | 可見 | 可見 | 可見 |
protected | 可見 | 可見 | 不可見 |
<無修飾符> | 可見 | 不可見 | 不可見 |
private | 不可見 | 不可見 | 不可見 |
表 1
不同的可見性級別限制了類或接口對其他類(例如不同的包或嵌套的包中的類)的可見性,也控制著子類對父類中定義的方法、函數(shù)方法及字段的可見與可訪問性。
在接下面的繼承,我們會(huì)看到父類中的定義對子類的可見性。
繼承繼承是面向?qū)ο缶幊痰暮诵母拍钪唬彩菢?gòu)造類的關(guān)系的基礎(chǔ)。憑借著類的可見性與可訪問性規(guī)則,通過繼承可實(shí)現(xiàn)易擴(kuò)展和維護(hù)的類層次關(guān)系。
語法上,Java 中實(shí)現(xiàn)繼承的方式是通過extends關(guān)鍵字后跟著父類名實(shí)現(xiàn)的。子類從父類中繼承所有public和protected的成員,如果子類與父類處于同一個(gè)包中,子類也將會(huì)繼承只有包訪問權(quán)限的成員。不過話說回來,在設(shè)計(jì)類時(shí),應(yīng)保持具有最少的公開方法或能被子類繼承的方法。下面通過Parent類和Child類來說明不同的可見性及達(dá)到的效果:
package com.javacodegeeks.advanced.design; public class Parent { // Everyone can see it public static final String CONSTANT = "Constant"; // No one can access it private String privateField; // Only subclasses can access it protected String protectedField; // No one can see it private class PrivateClass { } // Only visible to subclasses protected interface ProtectedInterface { } // Everyone can call it public void publicAction() { } // Only subclass can call it protected void protectedAction() { } // No one can call it private void privateAction() { } // Only subclasses in the same package can call it void packageAction() { } }
package com.javacodegeeks.advanced.design; // Resides in the same package as parent class public class Child extends Parent implements Parent.ProtectedInterface { @Override protected void protectedAction() { // Calls parent"s method implementation super.protectedAction(); } @Override void packageAction() { // Do nothing, no call to parent"s method implementation } public void childAction() { this.protectedField = "value"; } }
繼承本身就是一個(gè)龐大的主題, 在Java語言中也制定了一系列精細(xì)的規(guī)范。盡管如此,還是有一些易于遵循的原則幫助你實(shí)現(xiàn)精練的類層次結(jié)構(gòu)。在Java中,子類可以重載從父類中繼承過來的任意非final方法(final的概念參見Final類和方法)。
然而,起初在Java中并沒有特定的語法或關(guān)鍵字標(biāo)識方法是否是重載了的,這常常會(huì)給代碼的編寫引入混淆。因此后來引入了@Override注解用于解決這個(gè)問題:當(dāng)你確實(shí)是在重載繼承來的方法時(shí),請使用@Override注解進(jìn)行標(biāo)記。
另外一個(gè)Java開發(fā)者經(jīng)常需要權(quán)衡的問題在設(shè)計(jì)系統(tǒng)時(shí)使用類繼承(具體類或抽象類)還是接口實(shí)現(xiàn)。這個(gè)建議就是優(yōu)先選擇接口實(shí)現(xiàn)而非繼承。因?yàn)榻涌诟鼮檩p量,易于測試(通過接口mock)和維護(hù),并能降低修改實(shí)現(xiàn)所帶來的副作用。很多優(yōu)秀的編程技術(shù)都偏向于依賴接口為標(biāo)準(zhǔn)Java庫創(chuàng)建代理。
多重繼承不同于C++或其他編程語言,Java并不支持多重繼承:Java中的每個(gè)類最多只能有一個(gè)直接的父類(在使用Object的通用方法中我們知道Object類處于繼承層次的頂端)。然而Java中的類可以實(shí)現(xiàn)多個(gè)接口,所以實(shí)現(xiàn)多個(gè)接口是Java中達(dá)到多重繼承效果的唯一途徑。
package com.javacodegeeks.advanced.design; public class MultipleInterfaces implements Runnable, AutoCloseable { @Override public void run() { // Some implementation here } @Override public void close() throws Exception { // Some implementation here } }
盡管實(shí)現(xiàn)多個(gè)接口的方式非常強(qiáng)大,但有時(shí)為了更好的重用某個(gè)接口的實(shí)現(xiàn),你不得不通過更深的類繼承層次以達(dá)到多重繼承的效果:
public class A implements Runnable { @Override public void run() { // Some implementation here } }
// Class B wants to inherit the implementation of run() method from class A. public class B extends A implements AutoCloseable { @Override public void close() throws Exception { // Some implementation here } }
// Class C wants to inherit the implementation of run() method from class A // and the implementation of close() method from class B. public class C extends B implements Readable { @Override public int read(java.nio.CharBuffer cb) throws IOException { // Some implementation here } }
Java中引入的默認(rèn)方法在一定程序上解決了類繼承層次過深的問題。隨著默認(rèn)方法的引入,接口便不只是提供方法聲明約束,同時(shí)還可以提供默認(rèn)的方法實(shí)現(xiàn)。相應(yīng)的,實(shí)現(xiàn)了此接口的類也順帶著繼承了接口中實(shí)現(xiàn)的方法。示例如下:
package com.javacodegeeks.advanced.design; public interface DefaultMethods extends Runnable, AutoCloseable { @Override default void run() { // Some implementation here } @Override default void close() throws Exception { // Some implementation here } } // Class C inherits the implementation of run() and close() methods from the // DefaultMethods interface. public class C implements DefaultMethods, Readable { @Override public int read(java.nio.CharBuffer cb) throws IOException { // Some implementation here } }
多重繼承雖然很強(qiáng)大,卻也是個(gè)危險(xiǎn)的工具。眾所周知的"死亡鉆石(Diamond of Death)"就常作為多重繼承的主要缺陷被提及,所以開發(fā)者在設(shè)計(jì)類繼承關(guān)系時(shí)務(wù)必多加小心。湊巧Java 8接口規(guī)范里的默認(rèn)方法也同樣成了死亡鉆石的犧牲品。
interface A { default void performAction() { } } interface B extends A { @Override default void performAction() { } } interface C extends A { @Override default void performAction() { } }
根據(jù)上面的定義,下面的接口E將會(huì)編譯失敗:
// E is not compilable unless it overrides performAction() as well interface E extends B, C { }
坦白的說,作為面向?qū)ο缶幊陶Z言,Java一向都在盡力避免一些極端場景。然而避免語言本身的發(fā)展,這些極端場景也逐漸暴露。
繼承與組合好在繼承并非設(shè)計(jì)類的關(guān)系的唯一方式。組合是另外一種被大多開發(fā)者認(rèn)為優(yōu)于繼承的設(shè)計(jì)方法。其主旨也相當(dāng)簡單:取代層次結(jié)構(gòu),類應(yīng)該由其他類組合而來。
先看一個(gè)簡單的例子:
public class Vehicle { private Engine engine; private Wheels[] wheels; // ... }
Vehicle類由engine和wheels組成(簡單起見,忽略了其他的組成部分)。
不過也有人會(huì)說Vehicle也是一個(gè)engine,因此應(yīng)該使用繼承的方式:
public class Vehicle extends Engine { private Wheels[] wheels; // ... }
到底哪種設(shè)計(jì)才是正確的呢?業(yè)界通用的原則分別稱之為IS-A和HAS-A規(guī)則。IS-A代表的是繼承關(guān)系:子類滿足父類的規(guī)則,從而是父類的一個(gè)(IS-A)變量。與之相反,HAS-A代表的是組合關(guān)系:類擁有(HAS-A)屬于它的對象。通常,HAS-A優(yōu)于IS-A,原因如下:
設(shè)計(jì)更靈活,便于以后的變更
模型更穩(wěn)定,變化不會(huì)隨著繼承關(guān)系擴(kuò)散
依賴更松散,而繼承把父類與子類緊緊的綁在了一起
代碼更易讀,類所有的依賴都被包含在類的成員聲明里
盡管如此,繼承也有自己的用武之地,在解決問題時(shí)不應(yīng)被忽略。在設(shè)計(jì)面向?qū)ο竽P蜁r(shí),要時(shí)刻記著組合和繼承這兩種設(shè)計(jì)方法,盡可能多些嘗試以做出最優(yōu)選擇。
封裝在面向?qū)ο缶幊讨校庋b的含義就是把細(xì)節(jié)(像狀態(tài)、內(nèi)部方法等)隱藏于內(nèi)部而不暴露于實(shí)現(xiàn)之外。封裝帶來的好處就是提高了可維護(hù)性,并便于將來的變更。越少的細(xì)節(jié)暴露,就會(huì)帶來越多的未來變更實(shí)現(xiàn)的控制權(quán),而不用擔(dān)心破壞其他代碼(如果你是一位代碼庫或框架的開發(fā)者,一定會(huì)遇到這種情景)。
在Java語言中,封裝是通過可見性和可訪問性規(guī)則實(shí)現(xiàn)的。公認(rèn)的優(yōu)秀實(shí)踐就是從不直接暴露類的字段,而是通過setter(如果字段沒有聲明為final)和getter的方式來訪問它。請看下面的例子:
package com.javacodegeeks.advanced.design; public class Encapsulation { private final String email; private String address; public Encapsulation( final String email ) { this.email = email; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getEmail() { return email; } }
類似例子中定義的類,在Java中稱作JavaBeans:遵循"只能以setter和getter方法的方式暴露允許外部方法的字段"規(guī)則的普通Java類。
如我們在繼承部分強(qiáng)調(diào)過的,遵守封裝原則,把公開的信息最小化。不需要public的時(shí)候, 要使用private替代(或者protected/package/private,取決于具體的問題場景)。在將來的維護(hù)過程,你會(huì)得到回報(bào):帶給你足夠的自由來優(yōu)化設(shè)計(jì)而不會(huì)引入破壞性的變更(或者說對外部的變更達(dá)到最小化)。
Final 類和方法在Java中,有一種方式能阻止類被其他類繼承:把類聲明為final。
package com.javacodegeeks.advanced.design; public final class FinalClass { }
final修飾在方法上時(shí),也能達(dá)到阻止方法被重載的效果:
package com.javacodegeeks.advanced.design; public class FinalMethod { public final void performAction() { } }
是否應(yīng)該使用final修飾類或方法并無定論。Final的類和方法一定程度上會(huì)限制擴(kuò)展性,并且在設(shè)計(jì)之初很難判斷類是否會(huì)被繼承、方法是否能被重載。對于類庫開發(fā)者,尤其值得注意,使用final可能會(huì)嚴(yán)重影響類庫的適用性。
Java標(biāo)準(zhǔn)庫中有一些final類的例子,例如眾所周知的String類。在很早時(shí)候,就把String設(shè)計(jì)成了final,從而避免了開發(fā)者們自行設(shè)計(jì)的好壞不一的字符串實(shí)現(xiàn)。
源碼下載可以從這里下載本文中的源碼:advanced-java-part-3
下章概要在本章節(jié)中,我們學(xué)習(xí)了Java中的面向?qū)ο笤O(shè)計(jì)的概念。同時(shí)簡單介紹了基于契約的開發(fā)方式,涉及了一些函數(shù)式編程概念,也看到了編程語言隨著時(shí)間的演進(jìn)。在下一章中,我們將會(huì)學(xué)習(xí)到泛型編程,以及如何實(shí)現(xiàn)類型安全的編程。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/65487.html
摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:責(zé)任鏈模式的具體運(yùn)用以及原理請參見筆者責(zé)任鏈模式改進(jìn)方式引入適配器模式關(guān)于接口適配器模式原理以及使用場景請參見筆者適配器模式。 1 責(zé)任鏈模式現(xiàn)存缺點(diǎn) 由于責(zé)任鏈大多數(shù)都是不純的情況,本案例中,只要校驗(yàn)失敗就直接返回,不繼續(xù)處理接下去責(zé)任鏈中的其他校驗(yàn)邏輯了,故而出現(xiàn)如果某個(gè)部分邏輯是要由多個(gè)校驗(yàn)器組成一個(gè)整理的校驗(yàn)邏輯的話,則此責(zé)任鏈模式則顯現(xiàn)出了它的不足之處了。(責(zé)任鏈模式的具體運(yùn)...
閱讀 3601·2021-11-23 09:51
閱讀 1473·2021-11-04 16:08
閱讀 3547·2021-09-02 09:54
閱讀 3616·2019-08-30 15:55
閱讀 2594·2019-08-30 15:54
閱讀 958·2019-08-29 16:30
閱讀 2047·2019-08-29 16:15
閱讀 2317·2019-08-29 14:05