2012-06-06 22 views
1

我有一個A類,其實例變量類型爲X在子類中向下轉換Objective-C實例變量

@interface A : NSObject { 
    X *x; 
} 
@end 

一些X實例的附加符合的協議P。我想要爲那些X實例專門實現A版本。

@interface B : A { 
    X <P> *x; 
} 
@end 

這編譯得很好。但是,當我從B實例訪問x時,更改不會傳播到A。因此,未重新定義的A的功能使用其他X實例,而不是B的功能。

  • 當僅添加協議時是否可以重新定義實例變量? 有關於亞類的類似question。但是,子類和協議並不相同。雖然我的方法編譯得很好,但它不能按預期工作。

  • 如果這是不可能的:是否有共同的模式來執行此操作?

    1. 如果我不重寫新類型的實例變量,代碼凌亂難看的東西:如果我重寫實例變量

      [((X <P> *)x) methodOfP] 
      
    2. ,我將更改傳播自己到超類A。這需要額外的功能。

    3. 使用一個屬性而不是一個實例變量:這是否會生效?一個屬性是否可以在一個子類中重新定義?

      @interface A : NSObject { 
          X *x; 
      } 
      @property (strong, nonatomic) X *x; 
      @end 
      @implementation A 
      - (X *)x 
      { 
          return x; 
      } 
      - (void)setX:(X *)anX 
      { 
          x = anX; 
      } 
      @end 
      
      @interface B : A 
      @property (strong, nonatomic) X <P> *x; 
      @end 
      @implementation B 
      @end 
      

回答

0

最簡單的解決辦法是隱藏的實例變量。

@interface A() 
{ 
    X *x; 
} 
@end 

或實施的頭:

@implementation A 
{ 
    X *x; 
} 
//methods go here 
@end 

你不應該訪問超伊娃您可以通過移動從接口實例變量的類延續實現文件中做到這一點直接。請使用super.propertyName。然後,您可以將方法添加到您的子類,返回x只有當它實現了協議:

-(X*<protocol>)xThatImplementProtocol 
{ 
    X *x = super.x; 

    return ([x conformsToProtocol:protocol]) ? x : nil; 
} 

但是,這種方法會斷裂多態性。

說實話,我認爲你會用不同的方法,可能是組合,來解決這個問題。子類似乎不是天作之合。

1

你試圖做的事違反了面向對象編程的基本原則Liskov Substitution Principle。 B的一個實例可以傳遞給期望A的任何代碼,並且該代碼有權將它視爲A.這意味着它可以在該對象上調用-setX:,傳遞一個X 的實例,而不需要該對象符合協議P

換句話說,你想創建一個的子類,是不是A.

要做到這一點提出了一種設計混亂的事實。你應該退後一步並重新思考。首先,僅根據其接口設計所有類,並確保它們的接口在繼承方面有意義。然後才考慮實施。

+0

是的,但' - setX:'的子類實現可能與基類中的不同,並且可能完全不同。 – Etan

+0

另外,在我的情況下,只有'-x'方法公開地公開,因爲該屬性在公共頭中是隻讀的。 – Etan

+0

「-setX:」的子類實現「完全不同」 - 恰恰違背了我指出的LSP。而你上面的代碼片段不會使屬性爲只讀。它沒有太大的區別。對於一個子類來說,它的約束比其超類更窄是沒有意義的。一個子類應該是一個超類型的,具有更廣泛的可能操作。也許你應該解釋真正的類和協議應該是什麼,以及爲什麼你要這樣做。我懷疑你濫用協議的概念。 –