這個想法本身很健全。但是,如果你使根類型(這裏:NumberSet
)包私有,它將不起作用。要麼公開該類型,要麼使用公共接口。實際的實現類型應該(並且可以)被隱藏。
public abstract class NumberSet {
// Constructor is package private, so no new classes can be derived from
// this guy outside of its package.
NumberSet() {
}
}
public class Factories {
public NumberSet range(int start, int length) {
return new RangeNumberSet(start, length);
}
// ...
}
class RangeNumberSet extends NumberSet {
// ... must be defined in the same package as NumberSet
// Is "invisible" to client code
}
編輯爲了揭露從公共API隱藏/私有根型是一個錯誤。考慮以下情況:
package example;
class Bar {
public void doSomething() {
// ...
}
}
public class Foo {
public Bar newBar() {
return new Bar();
}
}
並考慮使用此API的客戶端應用程序。客戶可以做什麼?它不能正確聲明變量的類型爲Bar
,因爲該類型對包example
以外的任何類都是不可見的。它甚至不會調用Bar
實例上的方法,因爲它不知道存在這樣的公共方法(它看不到該類,更不用說它暴露的任何成員)。所以,最好的客戶可以在這裏做的是這樣的:
Object bar = foo.newBar();
這實質上是無用的。不同的是擁有一個公共接口(或抽象類)而不是私有包,就像上面定義的代碼一樣。在這種情況下,客戶端可以通過聲明NumberSet
類型的變量。它不能創建自己的實例或派生子類,因爲構造函數是隱藏的,但它可以訪問定義的公共API。
再次編輯即使您想要一個「無特徵」的值(從客戶端的角度來看),即一個沒有定義客戶端可能想要調用的有趣API的值,仍然是一個好主意按照上述方式公開基礎類型。只是爲了編譯器能夠執行類型檢查並允許客戶機代碼將這樣的值臨時存儲到(正確聲明的)變量中。
如果你不想讓你的客戶端調用任何類型的API方法:沒關係。沒有什麼能夠阻止你在你的(否則)公共基礎類型上提供一個公共API。只是不要聲明任何。使用「空的」抽象基類(從客戶端角度來看是空的,因爲所有感興趣的方法都是封裝私有的,因此是隱藏的)。但是你必須提供一個公共基類型,否則你應該使用普通的Object
作爲返回值,但是在編譯時你會放棄錯誤檢查。經驗法則:如果客戶端必須調用某種方法才能獲取值並將其傳遞給其他API,那麼客戶端實際上知道知道,這裏有一些神奇的特殊值。它必須能夠以某種方式處理它(至少「傳遞它」)。除了(完全合適的)編譯器警告之外,沒有爲客戶端提供正確的類型來處理這些值不會爲您購買任何東西。
public abstract class Specification {
Specification() {
// Package private, thus not accessible to the client
// No subclassing possible
}
Stuff getInternalValue1() {
// Package private, thus not accessible to the client
// Client cannot call this
}
}
就客戶端代碼而言,上面的類是「空的」它除了提供Object
已提供的東西外,不提供可用的API。擁有它的主要好處是:客戶端可以聲明這種類型的變量,並且編譯器能夠輸入檢查。不過,您的框架仍然是唯一可以創建此類型的具體實例的地方,因此您的框架可以完全控制所有值。
爲什麼它不起作用,如果我們讓root類型的package-private? – 2010-05-01 08:42:42
是的,但它是不需要的客戶端看到這種類型。我們只需要通過工廠方法進行規範,並通過工廠方法傳遞Schedule對象。 – 2010-05-03 11:02:07