[英]Derive & Destroy Encapsulation, or Violate DRY?
我有兩個 C++ 類: Sequence
,就像std::vector
和File
,它是代表機器上文件的字符串Sequence
。
從Sequence
派生File
是不費吹灰之力的。 它的行為完全相同,但增加了讀取和寫入文件的功能。 File
特定的功能很容易實現,無需將Sequence
的數據成員標記為受保護。 相反,它們可以是私有的,並且File
可以使用Sequence
的公共接口。 到處都是快樂的時光。
我想制作一個內部管理動態分配的 memory 的Array
class。 無法調整Array
object 的大小; 大小在構造函數中指定。*
這就是事情變得有爭議的地方。
從概念上講,從Array
派生Sequence
是有意義的。 就像File
是一個具有讀取和寫入文件的附加功能的Sequence
Sequence
一個具有按需調整大小的附加功能的Array
。
但有一個關鍵區別:調整大小功能需要直接訪問正在管理的 memory Array
。 換句話說,以前的私有成員現在必須受到保護。
使用受保護成員而不是私有成員會破壞封裝。 Array
和Sequence
之間的鏈接是唯一需要它的鏈接; 作品中的其他類可以只使用它們父母的公共接口。 從這個意義上說,推導是個壞主意。
您可能會爭辯說,想要 arrays 的人可以只使用Sequence
並忽略調整大小的功能。 但是話又說回來,您可以只使用File
並忽略讀/寫功能。 這就像購買一台筆記本電腦,但從未將其從辦公桌上移開。 這根本沒有意義。
最好的舉措是什么:派生並可能破壞封裝; 使Array
成為一個完全獨立的 class,並且必須毫無意義地重新實現很多功能; 還是完全忘記Array
而只是讓人們使用Sequence
?
*請注意,這是一個娛樂和教育項目,因此具有不可調整大小的動態分配數組的實用性無關緊要。
您可能會考慮將問題切入稍微不同的方向。 而不是 inheritance,也許這個問題可以用一個模板來解決——具體來說,一個管理集合緩沖區的策略模板。 您將擁有(至少)兩種實現方式:一種用於固定分配,另一種用於自動調整大小。
這根本不會破壞封裝,而且我可以看到兩者之間幾乎唯一的重疊是初始分配可能大致相同,無論是固定的還是可變的。 鑒於這是多么微不足道,我懷疑是否值得花費大量時間或精力來嘗試將其排除在外。 理論上可能是這樣,但至少在典型情況下,我們談論的是一行代碼,而且是非常簡單的一行代碼。
暫時回到 inheritance 問題,歸結為:這非常類似於標准圓形與橢圓形的情況,其中一個看起來像另一個,但最終兩者都不滿足 LSP - 你不能安全地將任何一個視為另一個,因此(至少是公開的)inheritance 不適合。 私有 inheritance 不需要遵循 LSP,但通常僅在/如果您需要/想要覆蓋基類的虛擬 function 時有用,這在這里似乎也不太可能。
我不會在這里使用推導。
Sequence
並不是真正的Array
。 雖然實際上它們似乎有許多常用方法,但從設計的角度來看,它們有非常不同的用途和保證。
但是,在Sequence
中使用Array
並讓Sequence
直接將多個調用(內聯)轉發到Array
是有意義的:
template <typename T>
class Sequence
{
public:
Sequence(): _array(10) {}
explicit Sequence(size_t n): _array(n) {}
bool empty() const { return _size == 0; }
size_t size() const { return _size; }
size_t capacity() const { return _array.size(); }
private:
size_t _size; // current size
Array<T> _array;
}; // class Sequence
注意:我在這里假設 Array 是同時使用其所有元素構建的,而序列將一次添加一個
同樣, File
從Sequence
派生是否有意義? 您是否沒有實現問題,例如將Sequence
的內容與磁盤表示同步?
好吧,在您的情況下,使用公共inheritance 從Array
派生Sequence
絕對是個壞主意(從矩形派生正方形)。 就面向對象編程而言,Sequence IS NOT an Array,因為Array
具有Sequence
所沒有的屬性,它是: An Array object cannot be resized
。 如果進行推導,就會破壞Liskov 替換原則。
在您的情況下,由於您想要實現一些功能,已經存在於另一個 class 中,我建議您使用私有inheritance (這意味着 inheritance 的實現),或存儲Sequence
的私有區域組合和例如Array
將其用於內部實現。
UPD:但是,在我看來,使用Array
實現Sequence
也很成問題。 也許最好創建一些抽象的基礎 class Container
來實現Sequence
和Array
的通用功能,然后從中派生這兩個類。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.