2011-12-04 74 views
5

我有三個類,一個抽象用戶和兩個特定的:NormalUser持有一個或多個地址對象的ArrayList可以不同(國內,國際,自定義等),然後具有返回true的方法的Admin類。它們都包含更多彼此無關的方法。Java繼承和避免不斷使用instanceof

abstract class User{ 
    public User(String username, String pw){ 
... 

} 

public class NormalUser extends User{ 
... 
    private ArrayList<Address> addresses; 

... 

    public void addAdress(ArrayList<Address> address){ 
     addresses.addAll(address); 
} 

public class Admin extends User{ 

... 
    public boolean getIsAdmin(){ 
     return true; 
    } 
} 
另一類

現在,如果我讓4個用戶對象像這樣的例子:

ArrayList<User> users; 

    users.add(new NormalUser("1", "pw"); 
    users.add(new NormalUser("2", "pw"); 
    users.add(new NormalUser("3", "pw"); 
    users.add(new NormalUser("4", "pw"); 
    users.add(new Admin("5", "pw")); 
    users.add(new NormalUser("6", "pw"); 

而且說我想用在NormalUser的addAddress方法,那麼我不得不垂頭喪氣的specfic用戶用戶NormalUser,我纔可以使用addAddress方法NormalUser這樣的:

 if (user instanceof NormalUser){ 
     NormalUser normal = (NormalUser) user; 
     normal.addAddress(...) 
     } 

爲什麼我想NormalUser和管理既要用戶的原因是這樣我就可以對其進行處理

我想將addEmail添加到User類中,然後在NormalUser類中重寫它,但是我必須對NormalUser類中的每個方法都這樣做,再加上Admin將從用戶以及它不需要該功能時。

問題1:有沒有更好的方法來做到這一點,因爲我聽說使用instanceof是一件壞事?我每次使用特定於NormalUser類的方法時都必須使用instanceof。

Quesiton 2:對象的ArrayList地址是將RegularUser鏈接到特定地址/(對象)的最佳方式嗎?

目前沒有涉及數據庫。

因此,例如,用戶有2個地址中的一個國內和國際的一個,和用戶B只擁有國內地址,用戶C具有國內和自定義地址等

感謝。

PS。我已經廣泛搜索了以前的帖子,但沒有找到解決方案。在我的兩本Java書籍中,他們都展示了使用instanceof的例子,但沒有提到它是一種不好的做法。

+0

對於這個特定的情況,恐怕我不能說哪個更好,但是不,'instanceof'在定義上並不是一件壞事。當多態性更合適時,您不應該過度使用它。 –

+0

與'instanceof'相關:你應該重新考慮你的設計,這樣你就不會在基本的'User'上調用'addAddress'。當你在一個專門爲'NormalUser'設計的代碼塊中時,你只應該調用這樣的方法。 – toto2

+0

有什麼理由讓管理員沒有地址? – soulcheck

回答

3

您可以使用Visitor pattern - 有點笨拙並且稍微難以理解,但可能是您的問題的最佳解決方案。

其實你的解決方案將addEmail推到基類並沒有那麼糟糕。只需在基地User中提供一個空的實施方案,並在RegularUser中覆蓋。如果您想要檢查給定的User實例是否支持添加電子郵件,請提供另一種方法,如supportsAddEmail默認返回false,當重寫addEmail時提供true

+0

但不會管理員繼承addAddress(即使它是空的)? – Brah

+0

是的,這意味着你可以調用不做任何事的'Admin.addEmail()'(無操作)。這就是爲什麼我建議'supportsAddEmail'的原因,但它看起來並不是一個好主意。這不正是你想要的嗎?如果用戶是'NormalUser'則添加電子郵件,否則不做任何事情。 –

+0

我認爲在基類中添加'addEmail'是一個好主意,並且是無害的。關於它的無操作性質,你可以把它想象成「有人告訴管理對象關於一個電子郵件地址,如果管理員不在意,那就這樣吧。」如果你需要將'getEmail()'放在基類中,在這種情況下,某些實現將不得不拋出一個異常,我覺得這很難看。如果你這樣做,至少有一個像supportsGetEmail()這樣的方法。最好的情況是,如果呼叫站點知道他們擁有哪個User子類,那麼只能將'getEmail()'添加到NormalUser。 – yshavit

0

我認爲最簡單的解決方案是創建一個類UserList,該類將包含一個NormalUser列表和一個Admin列表。類UserList的實例將替換原始列表。類的UserList可以提供一些方法,例如:

  • 用戶的getUser(索引i)//使用兩個列表實現

  • 用戶removeUser(索引i)//使用兩個列表實現

  • NormalUser getNormalUser(索引i)//與正常用戶列表
  • NormalUser removeNormalUser(索引i)//與正常用戶列表
  • 管理員getAdmin(索引i)來實現實施//實現與管理員用戶列表
  • 聯繫removeAdmin(索引i)//使用管理用戶列表
  • ....

處理適當列出了所有的代碼將在UserList類封裝實現。您可以使用同時使用這兩個列表或只有一個列表的方法,具體取決於您需要對用戶執行的操作。與UserList交互的類不知道在UserList中是否只有一個或兩個列表。

+0

感謝Phil的回覆,對我來說這似乎是一個好主意,但我希望不必爲了保存列表而創建一個新類。我是Java新手,但是例如我有一個動物超類,然後是一個貓和狗的子類。如果我有狗和貓的動物名單,並且我想對狗叫做樹皮(),那麼我將不得不創建一個狗的名單來做到這一點? - 對我來說似乎不直觀:/ – Brah

+0

你好。如果我在哪裏,我會創建(1)貓列表和(2)狗列表。考慮你有10000只狗和10000只貓。如果你把名單分開,找到所有的狗會更快,那麼如果你有一個單一的名單與20000個動物混合在一起。當你需要調用諸如bark()的方法時,你只需要處理狗的列表,而不是處理2萬個動物,並且在調用bark()之前必須檢查它們是否是狗或貓。如果您有很多元素,兩個列表的性能應該會更好。 – Phil