2016-08-05 55 views
2

你好Stackoverflowers,黑匣子和繼承

設想以下的基類

import java.util.ArrayList; 

public class Array 
{ 
    private ArrayList<Object> a = new ArrayList<Object>(); 

    public void add(Object element) 
    { 
    a.add(element); 
    } 

    public void addAll(Object elements[]) 
    { 
    for (int i = 0; i < elements.length; ++i) 
     a.add(elements[i]); // this line is going to be changed 
    } 
} 

而這裏的派生類:

public class ArrayCount extends Array 
{ 
    private int count = 0; 

    @Override 
    public void add(Object element) 
    { 
    super.add(element); 
    ++count; 
    } 

    @Override 
    public void addAll(Object elements[]) 
    { 
    super.addAll(elements); 
    count += elements.length; 
    } 
} 

的數組添加()添加一個元素到本地數組列表。 Array addAll()爲每個元素調用本地ArrayList添加。

ArrayCount add()調用其父級的add(),然後遞增計數。 ArrayCount addAll()調用其父級的addAll(),然後通過元素數遞增計數。

現在正在發生突變。在基類代碼的註釋行更改爲以下:

public void addAll(Object elements[]) 
    { 
    for (int i = 0; i < elements.length; ++i) 
     add(elements[i]); // this line was changed 
    } 

現在ArrayCount中的addAll()調用其父中的addAll(),它在內部調用的add()已被重寫的派生類。

Derived類的作者必須知道Base類是如何實現的。他們必須被告知Base類中的每一個變化,因爲它可能以不可預知的方式破壞他們的Derived類。

我正在尋找一種正確的方式來實現這一點,將尊重黑盒編程概念。因爲這個例子迫使派生類的編寫者知道基類是如何實現的並且知道每一個變化

+0

基類中的更改通過將調用虛擬化並將實現委託給派生類來顯式更改合約。你的問題不清楚。 –

+0

有沒有辦法做什麼?請澄清您的需求 –

+0

確實不清楚。我編輯了這個句子 –

回答

2

我假設你的意思是:「派生類的實現者必須不知道基類Array「。我會選擇使用代表團作爲可能是更好的方法裝飾器:

public class ArrayCount { 
    private int count = 0; 
    private Array a; 

    public ArrayCount(Array a) { 
    this.a = a; 
    } 

    public void add(Object element) { 
    a.add(element); 
    ++count; 
    } 

    public void addAll(Object elements[]) { 
    a.addAll(elements); 
    count += elments.length; 
    } 

} 

注:我離開了輸入參數檢查簡潔。

如果ArrayArrayCount都實現相同的接口,例如, IArray,你仍然可以使用類互換:

interface IArray { 
public void add(Object element); 
public void addAll(Object elements[]); 
} 
... 
Array implements IArray {...} 
ArrayCount implements IArray {...} 
0

馬克基類的方法爲final,但包括擴展支持的方法。

import java.util.ArrayList; 

public class Array { 
    private final ArrayList<Object> a = new ArrayList<Object>(); 

    public final void add(Object element) { 
     a.add(element); 
     afterAdd(element); 
    } 

    public final void addAll(Object[] elements) { 
     for (Object element : elements) { 
      a.add(element); 
     } 
     afterAddAll(elements); 
    } 

    protected void afterAddAll(Object[] elements) { 
     return; 
    } 

    protected void afterAdd(Object element) { 
     return; 
    } 

} 

所以當您使用黑匣子辦法一個子類只能重寫支持方法

public class ArrayCount extends Array { 
    private int count = 0; 

    @Override 
    protected void afterAdd(Object element) { 
    ++count; 
    } 

    @Override 
    protected void afterAddAll(Object[] elements) { 
    count += elements.length; 
    } 

} 
0

你只需要調用對象的方法,所以你不關心它是如何實現。

一個類的公共方法是一個合同定義你提供什麼和你得到什麼。

維護該類的開發人員可能會更改除合同或方法簽名以外的任何內容。

如果您擴展一個類,並且您將重寫一個或多個方法,那麼您應該關心類實現,因爲您將專門化該類的某些行爲。

要將具有相同接口的不同類進行徹底分離,應該使用java 接口,這樣每個開發人員都可以執行自己的業務邏輯實現。

當你知道某種方法可能是專用的時,你可以設計一個類可以從其他人擴展。

但是,如果你不想這樣做,你可以通過定義這些方法final來決定該方法不能被覆蓋。

通過這種方式,您告訴其他開發人員將使用您不希望擴展某些行爲的代碼。