開心一笑
【懸崖上一只小老鼠揮舞著短短的前爪,一次又一次跳下去,努力學習飛翔,旁邊母蝙蝠看著它摔的頭破血流,憂心的說:它爹,要不告訴它,它不是咱親生的!】
**提出問題******
項目中如何使用類和接口???
解決問題
使類和成員的可訪問性最小化
要區(qū)別設計良好的模塊與設計不好的模塊,最重要的因素在于,這個模塊對于外部的其他模塊而言,是否隱藏其內(nèi)部數(shù)據(jù)和其他實現(xiàn)細節(jié)。
第一原則很簡單:盡可能地使每個類或者成員不被外界訪問。換句話說,應該使用與你正在編寫的軟件的對于功能相一致的,盡可能最小的訪問級別。
對于頂級的類和接口,只有兩種可能的訪問級別:包級私有的(package-private)和公有的(public)。
對于成員,有四種訪問級別,具體的就不說了。
實例域決不能是公有的,特別是指向一個可變對象的。
例如:
//錯誤的
public static final Thing[] VALUES = { ... }
解決方法:
private static final Thing[] PRIVATE_VALUES = { .... }
public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
另一種解決方法是:添加一個公有方法,返回私有數(shù)組的一個備份:
private static final Thing[] PRIVATE_VALUES = { .... }
public static final Thing[] values(){
return PRIVATE_VALUES.clone();
}
總而言之,你應該始終盡可能地降低可訪問性。除了公有靜態(tài)final域的特殊情形之外,公有類都不應該包含公有域。并且要確保公有靜態(tài)final域所引用的對象都是不可以變得。
在公有類中使用訪問方法而非公有域
錯誤的:
class Point{
public double x;
public double y;
}
正確的:
class Point{
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}
總而言之,公有類永遠都不應該暴露可變得域,雖然還是有問題,但是讓公有類暴露不可變得域其危害性比較小。
使可變性最小
為了使類成為不可變,要遵循下面5條規(guī)則:
- 不要提供任何會修改對象狀態(tài)的方法
- 保證類不會被擴展(做法:讓類成為final類型)
- 使所有的域都是final的
- 使所有的域都成為私有的
- 確保對于任何可變組件的互斥訪問
不可變對象優(yōu)點:
- 不可變對象比較簡單
- 不可變對象本質(zhì)上是線程安全的,它們不要求同步。
- 不可變對象可以被自由分享
復合優(yōu)先于繼承
不用擴展現(xiàn)有的類,而是在新的類中增加一個私有域,它引用現(xiàn)有類的一個實例。這種設計稱做“復合”。
總結(jié):繼承的功能非常強大,但是也存在很多問題,因為它違背了封裝原則。只有當子類和超類之間確實存在子類型關(guān)系時,使用繼承才是恰當?shù)?。即使如此。如果子類和超類處在不同的包中,并且超類并不是為了繼承而設計的,那么繼承將會導致脆弱性。為了避免這種脆弱性,可以用復合和轉(zhuǎn)發(fā)機制來代替繼承,尤其是但存在適當?shù)慕涌诳梢詫崿F(xiàn)包裝類的時候。包裝類不僅比子類更加健壯,而且功能也更加強大。
具體例子可以看《Effective Java》書中的例子。
要么為繼承而設計,并提供文檔說明,要么就禁止繼承
關(guān)于程序文檔有句格言:好的API文檔應該描述一個給定的方法做了什么工作,而不是描述它是如何做到的。
標題說的挺明確的,用的比較少,具體就不多說明了。
接口優(yōu)于抽象類
類層次優(yōu)于標簽類
例如下面是一個標簽類:
class Figure{
enum Shape{RECTANGLE,CIRCLE}
final Shape shape;
double length;
double width;
double radius;
Figure(double radius){
shape = Shape.CIRCLE;
this.radius = radius;
}
Figure(double length,double width){
shape = Shape.RECTANGLE;
this.length = length;
this.width = width;
}
double area(){
switch (shape){
case RECTANGLE:
return length * width;
case CIRCLE:
return Math.PI * (radius * radius);
default:
throw new AssertionError();
}
}
}
標簽類過于冗長,容易出錯,并且效率低下。
改正后的代碼,下面是類層次:
abstract class Figure{
abstract double area();
}
class Circle extends Figure{
final double radius;
Circle(double radius){ this.radius = radius;}
double area(){ return Math.PI * (radius * radius);}
}
class Rectangle extends Figure{
final double length;
final double width;
Rectangle(double length,double width){
this.length = length;
this.width = width;
}
double area(){ return length * width;}
}
用函數(shù)對象表示策略
感覺工作用的比較少,具體可以看書本例子。
接口只用于定義類型
當類實現(xiàn)接口時,接口就充當可以引用這個類的實例的類型。因此,類實現(xiàn)類接口,就表明客戶端可以對這個類的實例實施某些動作。為了任何其他目的而定義接口是不恰當?shù)摹?/strong>
常量接口:接口沒有包含任何方法,它只包含靜態(tài)final域。
public interface ObjectStreamConstants {
/**
* Magic number that is written to the stream header.
*/
final static short STREAM_MAGIC = (short)0xaced;
/**
* Version number that is written to the stream header.
*/
final static short STREAM_VERSION = 5;
/* Each item in the stream is preceded by a tag
*/
}
常量接口模式是對接口的不良使用。
解決方案:
如果這些常量與某個現(xiàn)有的類或者接口緊密相關(guān),就應該把這些常量添加到這個類或者接口中。
簡而言之,接口應該只被用來定義類型,它們不應該被用來導出常量。
優(yōu)先考慮靜態(tài)成員類
嵌套類:是指被定義在另一個類的內(nèi)部的類。嵌套類有四種:靜態(tài)成員類,非靜態(tài)成員類,匿名類和局部類,除了第一種之外,其他三種都被稱為內(nèi)部類。
總結(jié):如果一個嵌套類需要在單個方法之外仍然是可見的,或者它太長了,不適合于放在方法內(nèi)部,就應該使用成員類。如果成員類的每個實例都需要一個指向其外圍實例的引用,就要把成員類做成非靜態(tài)的;否則做成靜態(tài)的。假設這個嵌套類屬于一個方法的內(nèi)部,如果你只需要在一個地方創(chuàng)建實例,并且已經(jīng)有了一個預置的類型可以說明這個類的特征,就要把它做成匿名類;否則,就做成局部類。
讀書感悟
來自亦舒《嘆息橋》
- 做不到是你自己的事,午夜夢回,你愛怎么回味就怎么回味,但人前人后,我要你裝出什么都沒有發(fā)生過的樣子。你可以的,我們都可以,人都是這般活下來的。
- 人生就像一座橋,我們從彼處來,往那邊去,一邊走一邊不住嘆息,因恨事太多。
- 這是我廿一年生命中前所未有的感覺,我高興到極限,耳邊有奇異的嗡嗡聲,內(nèi)心漲漲地飽滿,十分難以形容,但是,我沒有笑,我竟想哭,要盡很大的努力才把眼淚留在眼眶內(nèi)。發(fā)生了什么事?
- 沒有人愛我,會比你愛我更多。
其他
如果有帶給你一絲絲小快樂,就讓快樂繼續(xù)傳遞下去,歡迎轉(zhuǎn)載,點贊,頂,歡迎留下寶貴的意見,多謝支持!