2016-05-14 21 views
0
public interface IShoulders { 
    public void move(); 
} 

public class Body { 

public void createBody(){ 
    RightHand rightHand = new RightHand(); 
    rightHand.move(); 
    IShoulders leftHand = new LeftHand(); 
    leftHand.move(); 
} 

} 

public class RightHand implements IShoulders { 

    public void move(){ 
     System.out.println("Move Right Hand");   
    } 
} 

public class LeftHand implements IShoulders { 

public void move(){ 
    System.out.println("Move Left Hand");   
} 
} 
public class Main { 

public static void main(String[] args){ 

    Body myBody1 = new Body(); 
    myBody1.createBody(); 


    Body myBody2 = new Body(); 
    myBody2.createBody(); 
} 

} 

封裝作品請在類body如何當IShoulder leftHand = new LeftHand();的比較時使用了不同的封裝與RightHand rightHand = new RightHand();他們都做同樣的事情,所以當使用什麼和爲什麼它很重要解釋?謝謝如何在OOP

回答

0

它是什麼歸結到,當訪問一個字段,你可以立即訪問它,因爲它是立即鍵入。在這種情況下,當您將某個字段鍵入爲界面:IShoulders時,您只能直接訪問該界面定義的任何屬性/方法。當您訪問定義爲實現相同接口的類的字段時,定義並訪問爲RightHand的新字段不僅提供對由IShoulders定義的屬性/方法的訪問,還提供對RightHand類定義的擴展屬性/方法的訪問。

有了您的定義,有沒有真正的區別就在這裏一邊從值move()打印出來,而是採取了以下變化:

public class RightHand implements IShoulders { 

    public void move(){ 
     System.out.println("Move Right Hand");   
    } 
    public void Gesture() 
    { 
     System.out.println("Make a gesture with Right Hand"); 
    } 
} 

Gesture方法只能被定義爲RightHand現場訪問,它不會存在於僅定義爲IShoulders的字段中,即使您使用new RightHand()分配字段,也需要將該字段框或轉換爲RightHand以訪問新方法。

鑑於上述RightHand類的定義,請嘗試以下操作:

IShoulders shoulder = new RightHand(); 
shoulder.move(); // this will work fine... 
shoulder.Gesture(); // this will not be possible as "Gesture()" does not exist on IShoulders. 
((RightHand)shoulder).Gesture(); // this will work after casting shoulder as RightHand 
           // since the underlying object is actually a RightHand. 

然後嘗試以下操作:

RightHand rhand = new RightHand(); 
rhand.move(); // again, this works fine... 
rhand.Gesture(); // this now works fine too.. 

更進一步,該接口是您實現它的任何類合同。它只是說如果一個類實現了一個接口,它必須實現該接口中的所有內容。但是,它沒有說什麼,它應該如何實施。所以,只要類實現了接口的結構,那些實現的內容就可以完全爲每個類定製。

實現接口的替代方法是使用子類創建派生類。這看起來類似於實現接口,但是基類已經實現了屬性和方法。除非你不用virtual來修飾它們,否則它們可以被覆蓋,或者在另一個繼承層次上,你可以覆蓋並使用final修飾。

我;對不起,但讓我們調一​​下,因爲它仍然有點混亂。 當我寫IShoulder rightHand或RightHand rightHand i; m在創建它之前定義了 對象的類型?另外我一直想問 爲什麼我們需要定義一個類型,如果我們仍然使用新的關鍵字 就像我們對任何其他對象如集合所做的那樣?列表<> mylist = 新列表<>以及如何解決這個口頭? like object rightHand class RightHand封裝RightHand/IShoulder?糾正我,如果IAM 錯誤 - eersteam

當然,這樣的輸入變量 - 這允許編譯器(和程序員,對於這個問題),以強烈的定義可以用什麼,以及如何可以用在關心對象/價值。一個簡單的例子將是一個函數:

public string HyphenateTwoWords(string word1, string word2) 
{ 
    return string.Format("{0}-{1}", word1, word2); 
} 

上述函數有兩個string參數和在它們之間具有連字符一起加入他們。如果參數未輸入爲string,則可能傳入任何內容,結果在某些情況下可能只是錯誤,或者在其他情況下引發異常。由於它們被定義爲string,因此string.Format()調用沒有任何問題。現在

,在C#和其他語言,你實際上可以定義一般使用var一個字段/變量,例如:

List<string> myStringList = new List<string>(); 
myStringList.Add("Test1"); 
myStringList.Add("Test2"); 
myStringList.Add("Test3"); 
foreach(var item in myStringList) 
    Console.WriteLine(item); 

這讓編譯器推斷出的item的實際類型是基於什麼分配給它。但是,在大多數情況下,您不會真的想使用var。如果沒有其他原因,最好明確地鍵入你的變量,可讀性。查看變量的類型很容易,尤其是當您使用由多個開發人員維護的代碼時。此外,顯式輸入一個變量可以確保按預期使用該變量,否則會引發可處理的異常,或者在構建解決方案時編譯器會拋出錯誤或警告。

現在,關於上述的評論:

...如何將我知道,如果它的左手還是右手? 在我的例子中,雙手不是肩膀,而是手應該是 附加到應該因爲肩膀使他們能夠移動。 那麼你會如何實現呢? - eersteam

讓我們設計一些接口和類來說明它們的用途,我會作出一些改變/添加到你有什麼已經所有這些應該是相當直正向在AddLegs()方法看看在Body類看看LeftLeg也是如此。

public class BodyConstructor 
{ 
    public interface IBody 
    { 
     int Age { get; set; } 
     string Species { get; set; } 
     BodyPartGroup Head { get; set; } 
     BodyPartGroup Thorax { get; set; } 
     BodyPartGroup Abdomen { get; set; } 
     BodyPartGroup Pelvis { get; set; } 
    } 

    public interface IBodyPartGroup 
    { 
     BodyPartGroupType Type { get; set; } 
     List<IBodyPart> BodyParts { get; set; } 
    } 

    public interface IBodyPart 
    { 
     LateralDirection LateralOrientation { get; set; } 
     string Name { get; set; } 
     List<IBodyPart> SubParts { get; set; } 
     void Move(); 
    } 

    public enum BodyPartGroupType 
    { 
     Head = 1, 
     Thorax = 2, 
     Abdomen = 3, 
     Pelvis = 4, 
    } 

    public enum LateralDirection 
    { 
     Central = 0, 
     Right = 1, 
     Left = 2, 
    } 



    public class Body : IBody 
    { 
     public Body() 
     { 
      Head = new BodyPartGroup(BodyPartGroupType.Head); 
      Thorax = new BodyPartGroup(BodyPartGroupType.Thorax); 
      Abdomen = new BodyPartGroup(BodyPartGroupType.Abdomen); 
      Pelvis = new BodyPartGroup(BodyPartGroupType.Pelvis); 
     } 
     public Body(int age, string species) 
      : this() 
     { 
      Age = age; 
      Species = species; 
     } 
     public int Age { get; set; } 
     public string Species { get; set; } 
     public BodyPartGroup Head { get; set; } 
     public BodyPartGroup Thorax { get; set; } 
     public BodyPartGroup Abdomen { get; set; } 
     public BodyPartGroup Pelvis { get; set; } 

     public void AddLimbs() 
     { 
      AddArms(); 
      AddLegs(); 
     } 

     public void AddArms() 
     { 
      // Individual segments for the left arm 
      BodyPart leftShoulder = new BodyPart("Left Shoulder", LateralDirection.Left); 
      BodyPart leftArm = new BodyPart("Left Arm", LateralDirection.Left); 
      BodyPart leftHand = new BodyPart("Left Hand", LateralDirection.Left); 
      leftArm.SubParts.Add(leftHand); 
      leftShoulder.SubParts.Add(leftArm); 
      // Individual segments for the right arm 
      BodyPart rightShoulder = new BodyPart("Right Shoulder", LateralDirection.Right); 
      BodyPart rightArm = new BodyPart("Right Arm", LateralDirection.Right); 
      BodyPart rightHand = new BodyPart("Right Hand", LateralDirection.Right); 
      rightArm.SubParts.Add(rightHand); 
      rightShoulder.SubParts.Add(rightArm); 

      // Add arms to thorax 
      Thorax.BodyParts.Add(rightShoulder); 
      Thorax.BodyParts.Add(leftShoulder); 

     } 

     public void AddLegs() 
     { 
      // Individual segments for the left leg 
      BodyPart leftHip = new BodyPart("Left Hip", LateralDirection.Left); 
      LeftLeg leftLeg = new LeftLeg(); // Here we use the LeftLeg class instead, which inherits BodyPart 
      BodyPart leftFoot = new BodyPart("Left Foot", LateralDirection.Left); 
      leftLeg.SubParts.Add(leftFoot); 
      leftHip.SubParts.Add(leftLeg); 

      //Individual segments for the right leg 
      BodyPart rightHip = new BodyPart("Right Hip", LateralDirection.Right); 
      BodyPart rightLeg = new BodyPart("Right Leg", LateralDirection.Right); 
      BodyPart rightFoot = new BodyPart("Right Foot", LateralDirection.Right); 
      rightLeg.SubParts.Add(rightFoot); 
      rightHip.SubParts.Add(rightLeg); 

      // Add legs to pelvis 
      Pelvis.BodyParts.Add(leftHip); 
      Pelvis.BodyParts.Add(rightHip); 
     } 
    } 

    public class BodyPartGroup : IBodyPartGroup 
    { 
     public BodyPartGroup() 
     { 
      BodyParts = new List<IBodyPart>(); 
     } 
     public BodyPartGroup(BodyPartGroupType type) 
      : this() 
     { 
      this.Type = type; 
     } 
     public BodyPartGroupType Type { get; set; } 
     public List<IBodyPart> BodyParts { get; set; } 
    } 

    public class BodyPart : IBodyPart 
    { 
     public BodyPart() 
     { 
      SubParts = new List<IBodyPart>(); 
     } 
     public BodyPart(string name, LateralDirection orientation) 
      : this() 
     { 
      Name = name; 
      LateralOrientation = orientation; 
     } 
     // Location of body part: Left, Central, Right 
     public LateralDirection LateralOrientation { get; set; } 
     public string Name { get; set; } 
     public List<IBodyPart> SubParts { get; set; } 
     public virtual void Move() 
     { 
      // Common body part movement code. 
     } 
    } 

    public class LeftLeg : BodyPart 
    { 
     public LeftLeg() 
     { 
      Name = "Left Leg"; 
      LateralOrientation = LateralDirection.Left; 
     } 
     public override void Move() 
     { 
      // Custom left leg move code 

      base.Move(); // Call base BodyPart.Move(); 
     } 
    } 
} 
+0

我;對不起,但讓我們調一​​下,因爲它仍然有點混亂。當我寫IShoulder rightHand或RightHand rightHand i; m在創建它之前定義對象的類型?另外,我總是想問,爲什麼我們需要定義一個類型,如果我們正在使用new關鍵字,就像我們對任何其他對象如集合所做的那樣?列表<> mylist =新列表<>以及如何解決這個口頭?像RightHand類的對象rightHand封裝RightHand/IShoulder?糾正我,如果我錯了 – eersteam

+0

我已經更新了我的答案與關於輸入字段/變量的更多信息。我會盡量給你一些解釋,但是,這實際上是一個非常廣泛的主題,對於你在一本關於一般OOP約定和實踐的書或教程中閱讀可能會更好。 – gmiley

+0

對於「var」,我不太贊同。有些情況下它可能會隱藏你的類型,但是在大多數類型被聲明在賦值語句右邊的情況下,使用var可以提高可讀性和可維護性。 – bodangly

0

在你的例子中,leftHand是一個LeftHand,RightHand是一個RightHand。您創建的對象都是實現IShoulder的類的實例。兩個都是IShoulders,因此可以「移動」。 LeftHand和RightHand 變量之間的區別在於,您可以將LeftHand設置爲RightHand類的實例,因爲leftHand被聲明爲IShoulder,它可以是。如果你這樣做,然後調用leftHand.move(),它會移動右手。得到它?

界面讓你獲得的是能夠用任何一隻手工作而不需要知道你實際使用哪隻手。在你的例子中,如果你命名了IShoulder接口IHand,然後命名IHand變量而不是leftHand,它會更有意義。你的例子意味着雙手是肩膀。

但這不是封裝的意思。封裝只是將相關數據和作用於該數據的方法放在一起,並限制外部訪問僅影響其基本特性的組件(即隱藏細節)。因此,身體類可能會封裝頭部,手臂,腿部,軀幹等。手臂可能會封閉肩部,上臂,肘部,下臂和手部。你從外面看到的所有東西都是一個可以做你希望手臂做的事情的手臂。你需要使用Arm類而不知道或關心它是如何工作的。這裏有一個例子:

// the arm class encapsulates the parts of the arm (the data), and the behavior of the arm (the methods). 
class Arm 
{  
    Shoulder shoulder = new Shoulder(); 
    Hand hand = new Hand(); 
    UpperArm upperArm = new UpperArm(); 
    Elbow elbow = new Elbow(); 
    LowerArm lowerArm = new LowerArm(); 

    void poke() 
    {   
     flinch(); 
    } 

    void flinch() 
    { 
     // write some code that flinches the arm 
    } 

    void move() 
    { 
     // move the arm all over the place 
     shoulder.move(); 
     hand.wave(); 
     doHighFive(); 
     //... 
    } 

    void doHighFive() 
    { 
     // move all the arm parts in a high-five motion 
    } 
} 



// the Body class encapsulates the parts of the body (the data), and the behavior of the body (the methods). 
class Body 
{  
    Head head = new Head(); 
    Torso torso = new Torso(); 
    Arm leftArm = new Arm(); 
    Arm rightArm = new Arm(); 
    Leg leftLeg = new Leg(); 
    Leg rightLeg = new Leg(); 

    void poke() 
    {   
     flinch(); 
     dance(); 
     System.out.println("I didn't flinch, I was just dancing! Now I'm tired, though."); 
     goToBed(); 
    } 

    void flinch() 
    { 
     // write some code that makes the body flinch 
    } 

    void dance() 
    { 
     // write code to make the body dance 
    } 

    void goToBed() 
    { 
     // write code to make the body go to bed 
    } 
} 

你的問題,但是,似乎更多有關何時使用一個接口,而不是實現該接口的類之一。這更多的是關於抽象數據類型的問題,而不是封裝。抽象數據類型僅由其行爲(無代碼或數據)定義。接口是一種定義抽象數據類型的方法。這只是方法簽名的列表;把它看作是實施者如何行事的合同。

那麼你什麼時候使用接口?舉個例子,如果我的工作是遍歷一組身體部位並「戳」它們,我並不在乎你給我的具體類型的身體部位,我只需要戳它們。這裏有一個例子:

// IBodyPart defines an abstract data type that can be "poked", among other things. 
interface IBodyPart 
{ 
    void poke(); 
    //... 
} 

// maybe hands handle being poked by slapping 
class Hand implements IBodyPart 
{ 
    void poke() 
    {   
     slap(); 
    } 

    void slap() 
    { 
     // write some code that slaps 
    } 
} 

// maybe shoulders just flinch 
class Shoulder implements IBodyPart 
{ 
    void poke() 
    {   
     flinch(); 
    } 

    void flinch() 
    { 
     // write some code to flinch the shoulder 
    } 
} 

// etc. Each IBodyPart class has to implement the poke method. 

// I don't know nor do I care what I'm poking. I can do my job easily thanks to abstract data types! 
class Me 
{ 
    void PokeEmAll(List<IBodyPart> bodyPartList) 
    { 
     for (IBodyPart bodyPart : bodyPartList) 
     { 
      bodyPart.poke(); 
     } 
    } 
} 

class Main 
{ 
    // create a list of body parts so I can poke 'em all 
    static void main() 
    { 
     List<IBodyPart> bodyPartList = new List<IBodyPart>(); 
     Hand leftHand = new Hand(); 
     bodyPartList.add(leftHand); 
     Hand rightHand = new Hand(); 
     bodyPartList.add(rightHand); 
     Shoulder leftShoulder = new Shoulder(); 
     bodyPartList.add(leftShoulder); 
     Shoulder rightShoulder = new Shoulder(); 
     bodyPartList.add(rightShoulder); 

     Me me = new Me(); 
     me.PokeEmAll(bodyPartList); 
    } 
} 
+0

非常感謝,但是我怎麼知道它的左手還是右手呢?在我的例子中,雙手不是肩膀,而是手應該附在應該的位置上,因爲肩膀使他們能夠移動。那麼你將如何實現這一點? – eersteam

+0

在這種情況下,您需要一個名爲'Shoulder'的對象來實現'IShoulders',而'IShoulders'接口應該添加一個名爲'Arm'的屬性作爲IArm的新接口。我會用一個擴展的例子更新我的答案。 – gmiley

+0

@eersteam,如果你關心你是用左手還是用右手工作,你將不會使用界面。我認爲你的問題更多的是由於缺乏關於接口的知識,而不是關於封裝。在我試圖解決這個問題的地方查看我的更新。我將如何實現這一點?我會將所有其他身體部位的雙手和肩膀封裝在身體類中。如果所需的手部運動使得必要的話,身體(不是肩膀)將負責移動雙手,同時移動肩膀。 –