polymorphism คืออะไรใช้ทำอะไรและใช้อย่างไร?


564

polymorphism คืออะไรใช้ทำอะไรและใช้อย่างไร?


19
@John: +1 ฉันยอมรับว่าเป็นปรากฏการณ์ที่น่าสนใจที่สุด ฉันแน่ใจว่า Unkwntech ไม่ใช่คนที่มีความรู้และมีความสามารถเท่านั้นที่จะมีช่องว่างในสิ่งที่คนอื่น ๆ คิดว่าเป็นคำศัพท์ที่สนุกสนาน เพิ่งไปแสดงการเขียนโปรแกรมเป็นเรื่องที่กว้างมาก
AnthonyWJones

9
เขาอาจใช้มันโดยไม่ตั้งชื่อ
Aiden Bell

10
@Aamir: ฉันไม่แน่ใจว่ามีเหตุผลที่จะสมมติว่าคนที่มี 8k จะรู้วิธีการเขียนโปรแกรมทั้งหมดในทุกด้านของการเขียนโปรแกรม นอกจากนี้ฉันไม่คิดว่ามันบ่งบอกว่าระบบชื่อเสียงนั้นไม่สมบูรณ์ บางคนสามารถได้รับชื่อเสียงมากโดยถามคำถามที่ดีมากมาย ฉันคิดว่าการตอบสนองตามธรรมชาติของเราต่อการเปิดเผยนี้เพียงแค่แสดงให้เห็นว่าเรา (โปรแกรมเมอร์) มีแนวโน้มตามธรรมชาติที่จะใจแคบเล็กน้อย (ไม่ใช่เรื่องเลวร้ายเมื่อเราจำเป็นต้องเก่งในด้านเทคนิคเฉพาะ) และมีข้อเสีย
AnthonyWJones

43
พวกคุณดูเหมือนจะมีมุมมองที่ จำกัด ในการเขียนโปรแกรม ฉันรู้ว่าคนที่กำลังพัฒนาแบบฝังที่ไม่มีความรู้เกี่ยวกับ (หรือต้องการ) แนวคิด OO เลย สั้น ๆ ของพวกเขาคือการบิดทุกอะตอมของประสิทธิภาพการทำงานล่าสุดจากรหัสและที่ - รหัสที่พวกเขากำลังทำงานอยู่จะไม่เข้าสู่โลกของวัตถุและพวกเขาโชคดีที่ใกล้พอที่จะเกษียณอายุที่พวกเขาไม่ต้องกังวล การเรียนรู้แนวความคิดใหม่ ๆ เช่นวัตถุความหลากหลายและชื่อตัวแปรที่มีตัวอักษรมากกว่าสองตัว :-)
paxdiablo

29
วิธีไม่ให้คุณเรียนรู้อะไร? ไม่มีใครเข้ามาในโลกนี้รู้ PHP OOP และรูปแบบการออกแบบเพื่อให้ทุกท่านในบางจุดที่จะต้องเรียนรู้มันที่วิทยาลัยคำตอบที่นี่และอื่น ๆ ไม่ได้พูดคุยเกี่ยวกับคนที่ "ไม่กล้าที่จะรู้อยู่แล้วว่าขั้นตอนการรหัสที่ซับซ้อน "และพิจารณาว่าพวกเขาต้องการเรียนรู้ที่นี่ซึ่งเป็นสิ่งที่ดีและเป็นจุดของไซต์นี้ ใช้เวลาของคุณช่วยพวกเขาเพราะฉันแน่ใจว่าคุณได้รับความช่วยเหลือในอดีต หากตลอดประวัติศาสตร์ของมนุษย์แทนที่จะแบ่งปันความรู้การตอบสนองคือ "อะไรคุณไม่ทราบเหรอ? .. " เราทุกคนยังคงอยู่ในยุคมืด ..
เจมส์

คำตอบ:


544

หากคุณคิดถึงรากเหง้าของเทอมกรีกมันควรจะชัดเจน

  • โพลี = มากมาย: รูปหลายเหลี่ยม = หลายด้าน, สไตรีน = สไตรีนจำนวนมาก(a) , โพลิกอน = หลายภาษาและอื่น ๆ
  • Morph = การเปลี่ยนแปลงหรือรูปแบบ: สัณฐานวิทยา = การศึกษารูปแบบทางชีวภาพ, Morpheus = เทพเจ้าแห่งความฝันของกรีกสามารถใช้รูปแบบใดก็ได้

ดังนั้นความแตกต่างคือความสามารถ (ในการเขียนโปรแกรม) เพื่อนำเสนออินเทอร์เฟซเดียวกันสำหรับรูปแบบพื้นฐานที่แตกต่างกัน (ชนิดข้อมูล)

ตัวอย่างเช่นในหลายภาษาจำนวนเต็มและแพลทฟอลิซึมมีความหลากหลายโดยปริยายเนื่องจากคุณสามารถเพิ่มลบคูณและอื่น ๆ โดยไม่คำนึงถึงความจริงที่ว่าประเภทนั้นแตกต่างกัน พวกมันไม่ค่อยถูกมองว่าเป็นวัตถุในระยะปกติ

แต่ในทางเดียวกันว่าชั้นเหมือนBigDecimalหรือRationalหรือImaginaryยังสามารถให้การดำเนินงานดังกล่าวถึงแม้ว่าพวกเขาดำเนินการเกี่ยวกับข้อมูลต่างชนิด

ตัวอย่างคลาสสิกคือShapeคลาสและคลาสทั้งหมดที่สามารถสืบทอดได้ (สแควร์วงกลม dodecahedron รูปหลายเหลี่ยมที่ผิดปกติเครื่องหมายสีแดงและอื่น ๆ )

ด้วย polymorphism แต่ละคลาสเหล่านี้จะมีข้อมูลพื้นฐานที่แตกต่างกัน รูปร่างจุดต้องการเพียงสองพิกัด (สมมติว่ามันอยู่ในพื้นที่สองมิติของหลักสูตร) วงกลมต้องการจุดศูนย์กลางและรัศมี สี่เหลี่ยมจัตุรัสหรือสี่เหลี่ยมผืนผ้าต้องการพิกัดสองจุดสำหรับมุมซ้ายบนและล่างขวาและ (อาจ) การหมุน รูปหลายเหลี่ยมที่ผิดปกตินั้นต้องการเส้นจำนวนหนึ่ง

ด้วยการทำให้คลาสมีความรับผิดชอบสำหรับโค้ดรวมถึงข้อมูลคุณสามารถบรรลุความหลากหลายได้ ในตัวอย่างนี้ทุกคลาสจะมีDraw()ฟังก์ชั่นของตัวเองและรหัสลูกค้าสามารถทำได้:

shape.Draw()

เพื่อรับพฤติกรรมที่ถูกต้องสำหรับรูปร่างใด ๆ

นี้เป็นในทางตรงกันข้ามกับวิธีการแบบเก่าของการทำสิ่งที่มีรหัสที่ถูกแยกออกจากข้อมูลและคุณจะมีฟังก์ชั่นเช่นและdrawSquare()drawCircle()

การวางแนววัตถุความหลากหลายและการสืบทอดเป็นแนวคิดที่เกี่ยวข้องอย่างใกล้ชิด มี "กระสุนเงิน" มากมายในช่วงชีวิตการทำงานที่ยาวนานของฉันซึ่งโดยทั่วไปแล้วก็เลือนหายไป แต่กระบวนทัศน์ของ OO กลายเป็นสิ่งที่ดี เรียนรู้เข้าใจมันรักมัน - คุณจะดีใจที่คุณทำ :-)


(a)ตอนแรกฉันเขียนว่าเป็นเรื่องตลก แต่มันกลับกลายเป็นว่าถูกต้องและดังนั้นจึงไม่ใช่เรื่องตลก สไตรีนโมโนเมอร์เกิดขึ้นจากคาร์บอนและไฮโดรเจนและสไตรีนนั้นทำจากกลุ่มของมัน, .C8H8(C8H8)n

บางทีฉันควรจะพูดว่าโปลิปเป็นเหตุการณ์ที่เกิดขึ้นหลายครั้งของตัวอักษรpถึงแม้ว่าตอนนี้ฉันต้องอธิบายเรื่องตลกแล้วแม้ว่ามันจะดูไม่ตลกก็ตาม

บางครั้งคุณควรเลิกในขณะที่คุณอยู่ด้านหลัง :-)


50
กรีกไม่ใช่ละติน :) ('y' และ 'ph' เป็นของรางวัล) และในภาษากรีก 'morph-' เป็นเพียงแค่ 'รูปร่าง' หรือ 'รูปแบบ' - ภาษาอังกฤษความหมายของการเปลี่ยนแปลงรูปร่าง 'สำหรับ 'แปรเปลี่ยน' คือการพัฒนาต่อมา
AakashM

16
ความแตกต่างไม่เกี่ยวข้องกับ OOP แต่ OOP เกี่ยวข้องกับความหลากหลายเนื่องจากมันสนับสนุนโดยกำเนิด (สมมติว่าเป็นภาษา OOP ที่เหมาะสม) ดู FP สำหรับตัวอย่างอื่น ๆ ของ polymorphism
ทางเลือก

9
2 บรรทัดเหล่านี้ใช้กลอุบายของฉัน:Poly = many and Morph = change or form
โจ Smo

3
Polyp ย่อมาจาก polypo (u) s และเท้าเป็นภาษากรีก ;-)
เดิร์ก

2
@Shaun ฉันคิดว่าคุณอาจใช้คำว่า "interface" ในความหมายที่แท้จริงมากเกินไป / จำกัด - ฉันหมายถึงมันเป็นคำภาษาอังกฤษมากกว่าคำจำกัดความเฉพาะสำหรับภาษาคอมพิวเตอร์โดยพลการบางอย่าง มันไม่ได้หมายความว่าฟังก์ชั่นเดียวกันกับพารามิเตอร์เดียวกันทั้งหมดมันเป็นเพียงวิธีที่ส่งผลกระทบต่อ "วัตถุ" ในลักษณะเดียวกันโดยไม่คำนึงถึงประเภทคอนกรีตพื้นฐานของพวกเขา สิ่งนี้สามารถรวมวิธีการมากไปกับประเภทพารามิเตอร์ที่แตกต่างกันรวมถึงรูปแบบที่บริสุทธิ์มากขึ้นของความหลากหลาย
paxdiablo

250

ความแตกต่างคือเมื่อคุณสามารถถือวัตถุเป็นรุ่นทั่วไปของบางสิ่งบางอย่าง แต่เมื่อคุณเข้าถึงมันรหัสกำหนดประเภทที่แน่นอนมันเป็นและเรียกรหัสที่เกี่ยวข้อง

นี่คือตัวอย่างใน C # สร้างสี่คลาสภายในแอปพลิเคชันคอนโซล:

public abstract class Vehicle
{
    public abstract int Wheels;
}

public class Bicycle : Vehicle
{
    public override int Wheels()
    {
        return 2;
    }
}

public class Car : Vehicle
{
    public override int Wheels()
    {
        return 4;
    }
}

public class Truck : Vehicle
{
    public override int Wheels()
    {
        return 18;
    }
}

ตอนนี้สร้างสิ่งต่อไปนี้ใน Main () ของโมดูลสำหรับแอ็พพลิเคชันคอนโซล:

public void Main()
{
    List<Vehicle> vehicles = new List<Vehicle>();

    vehicles.Add(new Bicycle());
    vehicles.Add(new Car());
    vehicles.Add(new Truck());

    foreach (Vehicle v in vehicles)
    {
        Console.WriteLine(
            string.Format("A {0} has {1} wheels.",
                v.GetType().Name, v.Wheels));
    }
}

ในตัวอย่างนี้เราสร้างรายการของยานพาหนะระดับฐานซึ่งไม่ทราบว่ามีล้อจำนวนเท่าไหร่ในแต่ละกลุ่มย่อย แต่รู้ว่าแต่ละกลุ่มย่อยมีหน้าที่รับผิดชอบในการรู้จำนวนล้อที่มี

จากนั้นเราเพิ่มจักรยานรถยนต์และรถบรรทุกลงในรายการ

ถัดไปเราสามารถวนรอบยานพาหนะแต่ละคันในรายการและปฏิบัติต่อพวกเขาทุกอย่างเหมือนกันอย่างไรก็ตามเมื่อเราเข้าถึงคุณสมบัติของยานพาหนะ 'ล้อ' แต่ละชั้นยานพาหนะจะมอบหมายการใช้รหัสนั้นให้กับกลุ่มย่อยที่เกี่ยวข้อง

รหัสนี้มีการกล่าวถึงเป็น polymorphic เนื่องจากรหัสที่แน่นอนซึ่งถูกเรียกใช้งานจะถูกกำหนดโดยคลาสย่อยที่ถูกอ้างอิงที่รันไทม์

ฉันหวังว่านี่จะช่วยคุณได้


6
ฉันคิดว่านี่เป็นตัวอย่างที่ดีมากสำหรับการแสดงอินเทอร์เฟซหลักอย่างชัดเจนและมันไม่ได้จนกว่าวัตถุจะถูกสร้างเป็นอินสแตนซ์ที่จำเป็นต้องมีเวอร์ชันที่เป็นรูปธรรมเช่นรถ vs รถยนต์
wired00

1
ฉันจะบอกว่านี่เป็นตัวอย่างที่ชัดเจน แต่ถ้าคุณเป็นโปรแกรมเมอร์ PHP ลิงก์นี้อาจจะง่ายกว่าที่จะตรวจสอบ FIRST ก่อนแล้วยังดูที่นี้หลังจาก: code.tutsplus.com/tutorials/ …
Oliver Williams

นอกจากนี้ (เกินขอบเขตของ OP) เพื่อให้ทราบว่าเรากำลัง จำกัด การวิเคราะห์วัตถุที่รู้จัก เราไม่ได้ผ่านวัตถุ (เช่นไฟล์นำเข้า) แล้วกำหนดว่ามันคือประเภทใด (Excel, CSV, YAML, SQL, ฯลฯ ) การทำเช่นนี้จะต้องเรียงลำดับของระดับโรงงานบางอย่างสำหรับClass_Excel, Class_CSVจะเรียกว่าหรือมีReaderระดับที่เรียกว่า ไม่ว่าจะด้วยวิธีใดการทำซ้ำบางอย่างถ้า / จากนั้น / อื่นจะต้องถูกเก็บไว้ที่ใดที่หนึ่ง
Oliver Williams

@Antony Gibbs: นี่เป็นตัวอย่างที่ดีจริงๆ (รายการประเภททั่วไป) ที่สมเหตุสมผลกับฉัน .... มิฉะนั้นอะไรที่ทำให้การเรียนแต่ละคลาสมีล้อเป็นของตัวเองโดยไม่ต้องสืบทอดจากคลาสฐาน? มีแนวคิดอื่นนอกเหนือจากรายการที่ดีสำหรับ polymorphic หรือไม่
TTT

195

จากความเข้าใจและการประยุกต์ใช้ความหลากหลายใน PHPขอบคุณ Steve Guidetti

ความแตกต่างเป็นคำที่ยาวสำหรับแนวคิดที่ง่ายมาก

ความแตกต่างอธิบายรูปแบบในการเขียนโปรแกรมเชิงวัตถุที่เรียนมีฟังก์ชั่นที่แตกต่างกันในขณะที่ใช้งานร่วมกันของอินเตอร์เฟซ

ความสวยงามของพหุสัณฐานคือรหัสที่ทำงานกับคลาสที่แตกต่างกันไม่จำเป็นต้องรู้ว่าคลาสใดที่ใช้เนื่องจากมันใช้วิธีเดียวกันทั้งหมด การเปรียบเทียบโลกแห่งความจริงสำหรับความแตกต่างคือปุ่ม ทุกคนรู้วิธีใช้ปุ่ม: คุณเพียงแค่ใช้ความกดดัน อย่างไรก็ตามปุ่ม“ ทำ” ขึ้นอยู่กับสิ่งที่เชื่อมต่อและบริบทที่ใช้ - แต่ผลลัพธ์ไม่ส่งผลกระทบต่อวิธีการใช้งาน หากเจ้านายของคุณบอกให้คุณกดปุ่มคุณมีข้อมูลทั้งหมดที่จำเป็นในการทำงาน

ในโลกแห่งการเขียนโปรแกรม polymorphism ถูกใช้เพื่อทำให้แอพพลิเคชั่นเป็นโมดูลและขยายได้มากขึ้น แทนที่จะเป็นคำแถลงตามเงื่อนไขที่ยุ่งอธิบายหลักสูตรของการกระทำที่แตกต่างกันคุณสร้างวัตถุที่เปลี่ยนแทนได้ที่คุณเลือกตามความต้องการของคุณ นั่นคือเป้าหมายพื้นฐานของความหลากหลาย


10
ปุ่มนั้นไม่ได้มีความเกี่ยวข้องกับแนวคิดเรื่องนามธรรมมากขึ้นใช่ไหม
thewpfguy

6
แหล่งที่มาดั้งเดิม: code.tutsplus.com/tutorials/?hl=th
คน

8
@ Mantriur: นี่เป็นการลอกเลียนแบบจริงๆและเรามีกฎต่อว่า: stackoverflow.com/help/referencingแต่ได้รับคะแนนตอนนี้และความจริงที่ว่ากระทู้เก่าได้รับการยกเว้นจากการสูญเสียคำตอบในการลบคำตอบฉันไม่แน่ใจว่าจะลบหรือไม่ ตอนนี้ทันทีจะปรับปรุงอะไร ทางเลือกที่ดีที่สุดถัดไปคือเพียงแก้ไขในการแสดงที่มาในนามของผู้ใช้แม้ว่าฉันเชื่อมั่นอย่างยิ่งว่าผู้ใช้มีหน้าที่รับผิดชอบในการอ้างถึงแหล่งที่มาในคำตอบของพวกเขาเอง
BoltClock

1
ฉันเชื่อว่ามันไม่ถูกต้องที่จะบอกว่า polymorphism นั้นมีลักษณะเฉพาะสำหรับคลาสและ / หรือการเขียนโปรแกรมเชิงวัตถุการเห็นว่า ad hoc polymorphism หรือ parametric polymorphism นั้นไม่จำเป็นต้องมีคลาสและ / หรือวัตถุ ฉันคิดว่าสิ่งที่คำตอบนี้พูดถึงคือ subtyping (หรือที่เรียกว่า polymorphism ชนิดย่อยหรือ polymorphism แบบรวม)
StubbornShowaGuy

64

ถ้าใครบอกว่าตัดคนเหล่านี้

  1. ศัลยแพทย์
  2. ช่างทำผม
  3. นักแสดงชาย

อะไรจะเกิดขึ้น?

  • ศัลยแพทย์จะเริ่มทำการผ่า
  • ช่างทำผมจะเริ่มตัดผมของใครบางคน
  • นักแสดงจะหยุดแสดงทันทีจากฉากปัจจุบันโดยรอการชี้นำจากผู้กำกับ

ดังนั้นการเป็นตัวแทนข้างต้นแสดงให้เห็นถึงความหลากหลายคืออะไร (ชื่อเดียวกันพฤติกรรมที่แตกต่าง) ใน OOP

หากคุณกำลังจะไปสัมภาษณ์และผู้สัมภาษณ์ขอให้คุณบอก / แสดงตัวอย่างสดสำหรับความหลากหลายในห้องเดียวกันที่เรานั่งอยู่พูด -

คำตอบ - ประตู / Windows

สงสัยว่าอย่างไร

ผ่านประตู / หน้าต่าง - สามารถมาคนอากาศได้มาแสงสามารถมาฝนสามารถมา ฯลฯ

เพื่อให้เข้าใจได้ดีขึ้นและในลักษณะที่เรียบง่ายฉันใช้ตัวอย่างข้างต้น .. หากคุณต้องการการอ้างอิงสำหรับรหัสตามคำตอบข้างต้น


5
ฉันไม่คิดว่านี่เป็นตัวอย่างที่ดีเพราะอาจทำให้คนที่ไม่มีประสบการณ์คิดว่าถ้าสองคลาสมี.foo()วิธีการพวกเขาควรใช้อินเทอร์เฟซร่วมกันร่วมกัน อย่างไรก็ตามสิ่งนี้ไม่เป็นความจริงและนำไปสู่นามธรรมที่ไม่ถูกต้อง อินเทอร์เฟซควรกำหนดบทบาทที่จะเล่นซึ่งอาจมีการนำไปใช้ที่แตกต่างกันมากมาย แต่ทั้งหมดดึงมาจากชุดอินพุตเดียวกันและส่งคืนบางสิ่งจากชุดเอาต์พุตเดียวกัน การป้อนข้อมูลx.cut(...)สำหรับศัลยแพทย์สไตลิสต์หรือนักแสดงไม่เหมือนกันและไม่เป็นผลลัพธ์
Matt Klein

37

คำอธิบายง่ายๆโดยการเปรียบเทียบ

ประธานาธิบดีแห่งสหรัฐอเมริกาใช้พหุสัณฐาน อย่างไร? เขามีที่ปรึกษาหลายคน:

  1. ที่ปรึกษาทางทหาร
  2. ที่ปรึกษากฎหมาย
  3. นักฟิสิกส์นิวเคลียร์ (ในฐานะที่ปรึกษา)
  4. ที่ปรึกษาทางการแพทย์
  5. ฯลฯ

ทุกคนควรรับผิดชอบสิ่งเดียว: ตัวอย่าง:

ประธานาธิบดีไม่ใช่ผู้เชี่ยวชาญด้านการเคลือบสังกะสีหรือฟิสิกส์ควอนตัม เขาไม่รู้อะไรมากมาย - แต่เขารู้เพียงสิ่งเดียวเท่านั้น: วิธีการบริหารประเทศ

มันก็เหมือนกันกับรหัส: ความกังวลและความรับผิดชอบควรแยกออกจากชั้นเรียน / บุคคลที่เกี่ยวข้อง มิฉะนั้นคุณจะมีประธานาธิบดีรู้ทุกอย่างแท้จริงในโลก - วิกิพีเดียทั้งหมด ลองนึกภาพการมีวิกิพีเดียทั้งหมดในรหัสของคุณ: มันคงเป็นฝันร้ายที่ต้องรักษา

เหตุใดจึงเป็นความคิดที่ไม่ดีสำหรับประธานที่จะรู้สิ่งเหล่านี้ทั้งหมด

ถ้าประธานาธิบดีต้องบอกคนอื่นว่าจะทำอย่างไรนั่นก็หมายความว่าประธานาธิบดีต้องรู้ว่าต้องทำอะไร หากประธานาธิบดีต้องการทราบสิ่งที่เฉพาะเจาะจงด้วยตัวเองนั่นหมายความว่าเมื่อคุณต้องการเปลี่ยนแปลงคุณจะต้องทำในสองสถานที่ไม่ใช่เพียงอย่างเดียว

ตัวอย่างเช่นหาก EPA เปลี่ยนกฎหมายมลพิษแล้วเมื่อเกิดเหตุการณ์: คุณต้องทำการเปลี่ยนแปลงในระดับ EPA และระดับประธานาธิบดี การเปลี่ยนรหัสในสองแห่งแทนที่จะเป็นหนึ่งเดียวอาจเป็นอันตรายได้ - เนื่องจากยากต่อการบำรุงรักษามาก

มีแนวทางที่ดีกว่านี้ไหม?

มีวิธีการที่ดีกว่า: ประธานาธิบดีไม่จำเป็นต้องรู้อะไรเป็นพิเศษ - เขาสามารถขอคำแนะนำที่ดีที่สุดจากคนที่ได้รับมอบหมายให้ทำสิ่งเหล่านั้นโดยเฉพาะ

เขาสามารถใช้วิธี polymorphic ในการบริหารประเทศ

ตัวอย่าง - การใช้วิธี polymorphic:

ประธานทุกคนขอให้ทุกคนแนะนำเขา - และนั่นคือสิ่งที่เขาทำในชีวิตจริง - และนั่นคือสิ่งที่ประธานที่ดีควรทำ ที่ปรึกษาของเขาต่างตอบสนองต่างกัน แต่พวกเขาทุกคนรู้ว่าประธานาธิบดีหมายถึงอะไรโดย: Advise () เขามีคนหลายร้อยคนหลั่งไหลเข้ามาในห้องทำงานของเขา ไม่สำคัญว่าพวกเขาเป็นใคร ประธานทั้งหมดรู้ว่าเมื่อเขาขอให้ "แนะนำ" พวกเขารู้วิธีตอบสนอง :

public class MisterPresident
{
    public void RunTheCountry()
    {
        // assume the Petraeus and Condi classes etc are instantiated.
        petraeus.Advise(); // # Petraeus says send 100,000 troops to Fallujah
        condolezza.Advise(); // # she says negotiate trade deal with Iran
        healthOfficials.Advise(); // # they say we need to spend $50 billion on ObamaCare
    }
}

วิธีการนี้ทำให้ประธานาธิบดีสามารถบริหารประเทศได้อย่างแท้จริงโดยไม่ต้องรู้อะไรเกี่ยวกับเรื่องทางทหารหรือการดูแลสุขภาพหรือการทูตระหว่างประเทศ: รายละเอียดจะถูกทิ้งไว้ให้ผู้เชี่ยวชาญ สิ่งเดียวที่ประธานต้องรู้คือ: "คำแนะนำ ()"

สิ่งที่คุณไม่ต้องการ:

public class MisterPresident
{
    public void RunTheCountry()
    {
        // people walk into the Presidents office and he tells them what to do
        // depending on who they are.

        // Fallujah Advice - Mr Prez tells his military exactly what to do.
        petraeus.IncreaseTroopNumbers();
        petraeus.ImproveSecurity();
        petraeus.PayContractors();

        // Condi diplomacy advice - Prez tells Condi how to negotiate

        condi.StallNegotiations();
        condi.LowBallFigure();
        condi.FireDemocraticallyElectedIraqiLeaderBecauseIDontLikeHim();

        // Health care

        healthOfficial.IncreasePremiums();
        healthOfficial.AddPreexistingConditions();
    }
}

NO! NO! NO! ในสถานการณ์ข้างต้นประธานาธิบดีกำลังทำงานทั้งหมด: เขารู้เกี่ยวกับการเพิ่มจำนวนกองทหารและเงื่อนไขที่มีอยู่ก่อน ซึ่งหมายความว่าหากนโยบายตะวันออกกลางเปลี่ยนไปประธานาธิบดีจะต้องเปลี่ยนคำสั่งของเขาเช่นเดียวกับชนชั้น Petraeus เช่นกัน เราควรเปลี่ยนคลาสเพตราอุสเท่านั้นเพราะประธานาธิบดีไม่ควรต้องจมอยู่กับรายละเอียดแบบนั้น เขาไม่จำเป็นต้องรู้รายละเอียด สิ่งที่เขาต้องรู้ก็คือถ้าเขามีระเบียบหนึ่งสิ่งทุกอย่างจะได้รับการดูแล รายละเอียดทั้งหมดควรจะถูกทิ้งไว้กับผู้เชี่ยวชาญ

สิ่งนี้ทำให้ประธานทำสิ่งที่เขาทำได้ดีที่สุด: กำหนดนโยบายทั่วไปดูดีและเล่นกอล์ฟ: P

มันใช้งานอย่างไร - ผ่านคลาสพื้นฐานหรืออินเตอร์เฟสทั่วไป

นั่นคือผลที่ได้คือความหลากหลายในสรุป มันทำยังไงกันแน่? ผ่าน "การใช้อินเทอร์เฟซทั่วไป" หรือโดยใช้คลาสพื้นฐาน (การสืบทอด) - ดูคำตอบข้างต้นซึ่งรายละเอียดนี้ชัดเจนยิ่งขึ้น (เพื่อให้เข้าใจแนวคิดนี้ได้ชัดเจนยิ่งขึ้นคุณจำเป็นต้องรู้ว่าอินเทอร์เฟซคืออะไรและคุณจะต้องเข้าใจว่ามรดกคืออะไรหากปราศจากคุณอาจต้องดิ้นรน)

ในคำอื่น ๆ Petraeus, สภาพนั้นและ HealthOfficials ทั้งหมดจะเรียนที่ "ใช้อินเตอร์เฟซ" - ขอเรียกมันว่าอินเตอร์เฟซที่เพิ่งมีวิธีที่หนึ่ง:IAdvisor Advise()แต่ตอนนี้เรากำลังเข้าสู่ข้อมูลเฉพาะ

นี่จะเหมาะ

    public class MisterPresident
    {
            // You can pass in any advisor: Condi, HealthOfficials,
            //  Petraeus etc. The president has no idea who it will 
            // be. But he does know that he can ask them to "advise" 
            // and that's all Mr Prez cares for.

        public void RunTheCountry(IAdvisor governmentOfficer)
        {             
            governmentOfficer.Advise();              
        }
    }


    public class USA
    {
        MisterPresident president;

        public USA(MisterPresident president)
        {
            this.president = president;
        }

        public void ImplementPolicy()
        {
            IAdvisor governmentOfficer = getAdvisor(); // Returns an advisor: could be condi, or petraus etc.
            president.RunTheCountry(governmentOfficer);
        }
    }

สรุป

สิ่งที่คุณต้องรู้คือ:

  • ประธานาธิบดีไม่จำเป็นต้องรู้ข้อมูลเฉพาะ - คนเหล่านั้นถูกทิ้งให้คนอื่น
  • ประธานาธิบดีทุกคนต้องรู้คือการถามว่าใครเดินเข้ามาเพื่อแนะนำเขา - และเรารู้ว่าพวกเขาจะรู้ว่าต้องทำอย่างไรเมื่อถูกขอให้แนะนำ (เพราะพวกเขาทั้งหมดอยู่ในความเป็นจริงที่ปรึกษา (หรือ IAdvisors :))

ฉันหวังว่ามันจะช่วยคุณ หากคุณไม่เข้าใจสิ่งใดโพสต์ความคิดเห็นและฉันจะลองอีกครั้ง


4
ตัวอย่างที่ยอดเยี่ยม! ขอบคุณ
Iman Sedighi

1
การเปรียบเทียบที่น่าสนใจมาก ขอบคุณ.
thanhtang

1
@TTT เพราะ (1) ทุกครั้งที่คุณมีที่ปรึกษาใหม่ดังนั้นคุณต้องเปลี่ยนคลาสประธานาธิบดี - คุณไม่ต้องการทำการเปลี่ยนแปลง x2 แค่หนึ่ง. (2) ประการที่สองถ้าคุณต้องเปลี่ยนที่ปรึกษาที่มีอยู่คุณอาจต้องกลับไปและเปลี่ยนหนึ่งในสามสายดังกล่าวในชั้นเรียนของประธานาธิบดี - คุณต้องการเปลี่ยนเพียงครั้งเดียวไม่ใช่สองครั้ง (3) หากคุณมีการโทรแยกกันสามครั้งคุณจะต้องถามภายในชั้นเรียนของประธานาธิบดี: if healthAdvisor? then do this:และif petraus then do that etc.รูปแบบนี้จะต้องทำซ้ำและนั่นเป็นสิ่งที่ไม่จำเป็นและซับซ้อน ดูการแก้ไขด้านบน
BKSpurgeon

1
@TTT ใช่คุณพูดถูก แต่ฉันต้องค่อยๆแนะนำแนวคิดให้กับผู้อ่านไม่เช่นนั้นพวกเขาจะไม่เข้าใจ ฉันได้เพิ่มการเปลี่ยนแปลงเพิ่มเติม โปรดแนะนำหากต้องการคำชี้แจง
BKSpurgeon

1
@TTT คลาสพื้นฐานเทียบกับส่วนต่อประสานคือการตัดสินใจออกแบบโปรแกรมเมอร์ที่ต้องทำเมื่อทำ polymorpism ดูที่นี่สำหรับรายละเอียดเพิ่มเติม: stackoverflow.com/questions/56867/interface-vs-base-class
BKSpurgeon

24

ความแตกต่างคือความสามารถในการรักษาระดับของวัตถุราวกับว่ามันเป็นชั้นผู้ปกครอง

ตัวอย่างเช่นสมมติว่ามีคลาสที่ชื่อว่า Animal และคลาสที่ชื่อว่า Dog ที่สืบทอดมาจาก Animal ความแตกต่างคือความสามารถในการรักษาวัตถุสุนัขใด ๆ ที่เป็นวัตถุสัตว์เช่น:

Dog* dog = new Dog;
Animal* animal = dog;

ฉันสงสัยว่าสิ่งนี้เกี่ยวข้องกับคำอธิบายที่ได้รับความนิยม @Ajay Patel อย่างไรclasses have different functionality while sharing a common interface
BornToCode

1
@BornToCode คลาสพาเรนต์คือ / ให้ส่วนต่อประสานทั่วไปนั้น
grokmann

1
ความแตกต่างไม่จำเป็นต้องพิมพ์ย่อย
Shaun Luttin

22

polymorphism:

มันเป็นแนวคิดของการเขียนโปรแกรมเชิงวัตถุความสามารถของวัตถุที่แตกต่างกันในการตอบสนองแต่ละอย่างในแบบของตัวเองไปยังข้อความที่เหมือนกันเรียกว่า polymorphism

ความแตกต่างเป็นผลมาจากความจริงที่ว่าทุกชั้นมีชีวิตอยู่ใน namespace ของตัวเอง ชื่อที่กำหนดภายในคำจำกัดความของคลาสจะไม่ขัดแย้งกับชื่อที่กำหนดไว้ภายนอก นี่คือความจริงทั้งสองตัวแปรอินสแตนซ์ในโครงสร้างข้อมูลของวัตถุและวิธีการของวัตถุ:

  • เช่นเดียวกับเขตข้อมูลของโครงสร้าง C อยู่ในเนมสเปซที่ได้รับการปกป้องดังนั้นตัวแปรอินสแตนซ์ของวัตถุ

  • ชื่อวิธีได้รับการคุ้มครองด้วย ต่างจากชื่อฟังก์ชั่น C ชื่อวิธีไม่ใช่สัญลักษณ์สากล ชื่อของวิธีการในชั้นหนึ่งไม่สามารถขัดแย้งกับชื่อวิธีการในชั้นเรียนอื่น ๆ ; สองชั้นที่แตกต่างกันมากสามารถใช้วิธีการตั้งชื่อเหมือนกัน

ชื่อเมธอดเป็นส่วนหนึ่งของส่วนต่อประสานของวัตถุ เมื่อมีการส่งข้อความเพื่อขอให้วัตถุทำอะไรบางอย่างข้อความจะตั้งชื่อวิธีการที่วัตถุควรทำ เนื่องจากวัตถุที่แตกต่างกันสามารถมีวิธีการที่มีชื่อเดียวกันความหมายของข้อความจะต้องเข้าใจความสัมพันธ์กับวัตถุเฉพาะที่ได้รับข้อความ ข้อความเดียวกันที่ส่งไปยังวัตถุที่แตกต่างกันสองรายการสามารถเรียกใช้สองวิธีที่แตกต่างกันได้

ประโยชน์หลักของความหลากหลายคือมันลดความซับซ้อนของอินเตอร์เฟสการเขียนโปรแกรม อนุญาตให้มีการจัดประชุมที่สามารถนำกลับมาใช้ใหม่ในชั้นเรียนได้หลังเลิกเรียน แทนที่จะประดิษฐ์ชื่อใหม่สำหรับแต่ละฟังก์ชั่นใหม่ที่คุณเพิ่มเข้าไปในโปรแกรมชื่อเดียวกันสามารถนำกลับมาใช้ใหม่ได้ อินเตอร์เฟสการเขียนโปรแกรมสามารถอธิบายเป็นชุดของพฤติกรรมที่เป็นนามธรรมซึ่งค่อนข้างแตกต่างจากคลาสที่นำมาใช้

ตัวอย่าง:

ตัวอย่างที่ 1:นี่คือตัวอย่างง่ายๆที่เขียนในหลาม 2.x

class Animal:
    def __init__(self, name):    # Constructor of the class
        self.name = name
    def talk(self):              # Abstract method, defined by convention only
        raise NotImplementedError("Subclass must implement abstract method")

class Cat(Animal):
    def talk(self):
        return 'Meow!'

class Dog(Animal):
    def talk(self):
        return 'Woof! Woof!'

animals = [Cat('Missy'),
           Dog('Lassie')]

for animal in animals:
    print animal.name + ': ' + animal.talk()

ตัวอย่างที่ 2: ความหลากหลายถูกนำมาใช้ในJavaโดยใช้วิธีการมากไปและวิธีการเอาชนะแนวคิด

ขอให้เราพิจารณาตัวอย่างรถยนต์สำหรับพูดคุยเกี่ยวกับความแตกต่าง นำแบรนด์ใด ๆ เช่นฟอร์ดฮอนด้าโตโยต้า BMW เบนซ์ ฯลฯ ทุกอย่างเป็นรถประเภท

แต่แต่ละคนมีคุณสมบัติขั้นสูงของตัวเองและเทคโนโลยีขั้นสูงที่เกี่ยวข้องกับพฤติกรรมการย้ายของพวกเขา

ตอนนี้ให้เราสร้างรถยนต์ประเภทพื้นฐาน

Car.java

public class Car {

    int price;
    String name;
    String color;

    public void move(){
    System.out.println("Basic Car move");
    }

}

ให้เราใช้ตัวอย่างฟอร์ดคาร์

ฟอร์ดขยายประเภทรถเพื่อสืบทอดสมาชิกทั้งหมด (คุณสมบัติและวิธีการ)

Ford.java

public class Ford extends Car{
  public void move(){
    System.out.println("Moving with V engine");
  }
}

คลาสฟอร์ดข้างต้นขยายคลาสรถยนต์และใช้วิธีการย้าย () แม้ว่าฟอร์ดจะมีวิธีการขนย้ายผ่านมรดกอยู่แล้ว แต่ฟอร์ดก็ยังคงใช้วิธีนี้ในแบบของตัวเอง สิ่งนี้เรียกว่าการแทนที่เมธอด

Honda.java

public class Honda extends Car{
  public void move(){
    System.out.println("Move with i-VTEC engine");
  }
}

เช่นเดียวกับฟอร์ดฮอนด้ายังขยายประเภทของรถยนต์และนำวิธีการย้ายมาใช้ในแบบของตัวเอง

การแทนที่เมธอดเป็นคุณลักษณะที่สำคัญในการเปิดใช้งาน Polymorphism การใช้เมธอดการแทนที่ชนิดย่อยสามารถเปลี่ยนวิธีที่วิธีการทำงานพร้อมใช้งานผ่านการสืบทอด

PolymorphismExample.java

public class PolymorphismExample {
  public static void main(String[] args) {
    Car car = new Car();
    Car f = new Ford();
    Car h = new Honda();

    car.move();
    f.move();
    h.move();

  }
}

ความแตกต่างตัวอย่างเอาท์พุท:

ในวิธีการหลักของคลาส Polymorphism ตัวอย่างฉันได้สร้างวัตถุสามชิ้นคือรถยนต์ฟอร์ดและฮอนด้า วัตถุทั้งสามนั้นถูกอ้างอิงโดยประเภทรถ

โปรดทราบจุดสำคัญที่นี่ว่าประเภทซุปเปอร์คลาสสามารถอ้างถึงประเภทย่อยของวัตถุ แต่ไม่สามารถใช้ข้อรองได้ เหตุผลก็คือสมาชิกทั้งหมดของคลาสซุปเปอร์พร้อมใช้งานสำหรับคลาสย่อยโดยใช้การสืบทอดและในช่วงเวลาคอมไพล์คอมไพเลอร์พยายามที่จะประเมินว่าประเภทการอ้างอิงที่เราใช้มีวิธีที่เขาพยายามเข้าถึง

ดังนั้นสำหรับรถยนต์อ้างอิง f และ h ใน PolymorphismExample วิธีการย้ายมีอยู่จากประเภทรถยนต์ ดังนั้นคอมไพเลอร์ผ่านกระบวนการรวบรวมโดยไม่มีปัญหาใด ๆ

แต่เมื่อพูดถึงการดำเนินการรันไทม์เครื่องเสมือนจะเรียกใช้เมธอดบนวัตถุที่เป็นประเภทย่อย ดังนั้นวิธีการย้าย () ถูกเรียกจากการใช้งานที่เกี่ยวข้อง

ดังนั้นวัตถุทั้งหมดเป็นประเภทรถ แต่ในช่วงเวลาทำงานการดำเนินการขึ้นอยู่กับวัตถุที่เกิดการอุทธรณ์ สิ่งนี้เรียกว่า polymorphism


แนวคิดการบรรทุกเกินพิกัดไม่เกี่ยวข้องกับการสืบทอดและความหลากหลาย
srk

@srk Method overloading เป็นวิธีหนึ่งในการนำ polymorphism มาใช้ มันมักจะถูกจัดประเภทเป็นแบบคงที่หรือแบบเฉพาะกิจ wiki.c2.com/?CategoryPolymorphism
Shaun Luttin

12

โดยปกติแล้วนี่หมายถึงความสามารถของวัตถุประเภท A ที่จะทำตัวเหมือนวัตถุประเภท B ในการเขียนโปรแกรมเชิงวัตถุนี้มักจะเกิดจากการสืบทอด วิกิพีเดียบางลิงค์เชื่อมโยงเพื่ออ่านเพิ่มเติม:

แก้ไข: ลิงก์เสียคงที่


10
"ความสามารถของวัตถุประเภท A เพื่อทำตัวเหมือนวัตถุประเภท B" - ไม่ใช่คำจำกัดความที่แม่นยำ ผมจะบอกว่ามันมากขึ้นเช่นความสามารถในการรักษาวัตถุชนิดหนึ่งเหมือนมันวัตถุชนิดบี
Artem Barger

ใช่. บางทีนั่นอาจเป็นคำพูดที่ดีกว่า
JesperE

เพื่อความครบถ้วนหลายภาษาใช้ความหลากหลายในการพิมพ์เป็ดเช่น Python
ilya n

ฉันสงสัยว่าสิ่งนี้เกี่ยวข้องกับคำอธิบายที่ได้รับความนิยม @Ajay Patel อย่างไรclasses have different functionality while sharing a common interface
BornToCode

9

ความแตกต่างคือสิ่งนี้:

class Cup {
   int capacity
}

class TeaCup : Cup {
   string flavour
}

class CoffeeCup : Cup {
   string brand
}

Cup c = new CoffeeCup();

public int measure(Cup c) {
    return c.capacity
}

คุณสามารถผ่านเพียงแค่ถ้วยแทนอินสแตนซ์ที่เฉพาะเจาะจง สิ่งนี้ช่วยในการทั่วไปเนื่องจากคุณไม่จำเป็นต้องระบุอินสแตนซ์วัด () เฉพาะสำหรับถ้วยแต่ละประเภท


2
นี่คือความแตกต่างชนิดย่อยโดยเฉพาะ
Shaun Luttin

@ vinko-vrsalovic: การพัฒนาซอฟต์แวร์เป็นอย่างไรในชนบทอเมริกา?
TTT

8

ฉันรู้ว่านี่เป็นคำถามเก่าที่มีคำตอบที่ดีมากมาย แต่ฉันต้องการที่จะรวมคำตอบหนึ่งประโยค:

การรักษาประเภทที่ได้มาราวกับว่ามันเป็นประเภทพื้นฐาน

มีตัวอย่างมากมายที่แสดงการกระทำนี้ แต่ฉันรู้สึกว่านี่เป็นคำตอบที่กระชับ


2
นี่คือ subtyping ซึ่งเป็น polymorphism ชนิดเดียวเท่านั้น
Shaun Luttin

@ShaunLuttin คุณสามารถชี้ให้ฉันไปยังแหล่งข้อมูลใด ๆ เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับความหลากหลายชนิดอื่นได้หรือไม่?
Abe Miessler

คือ "ad hoc polymorphism" และ "parameteric polymorphism" เพิ่มเติมจาก "subtype polymorphism"
Shaun Luttin

8

(ฉันกำลังอ่านบทความเกี่ยวกับสิ่งที่แตกต่างอย่างสิ้นเชิง .. และ polymorphism โผล่ขึ้นมา ... ตอนนี้ฉันคิดว่าฉันรู้ว่า polymorphism คืออะไร .... แต่เห็นได้ชัดว่าไม่ได้ในวิธีที่สวยงามนี้อธิบาย .. อยากเขียนลงที่ไหนสักแห่ง .. ยังดีกว่าจะแบ่งปัน ... )

http://www.eioba.com/a/1htn/how-i-explained-rest-to-my-wife

อ่านต่อจากส่วนนี้:

..... ความหลากหลาย นั่นเป็นวิธีที่เกินบรรยายว่าคำนามต่าง ๆ สามารถใช้คำกริยาเดียวกันกับพวกเขาได้


5

โดยทั่วไปแล้วมันเป็นความสามารถในการเชื่อมต่อกับวัตถุประเภทต่าง ๆ จำนวนมากโดยใช้ API ที่เหมือนกันหรือคล้ายกันอย่างพิถีพิถัน มีหลายรูปแบบ:

  • ฟังก์ชั่นโอเวอร์โหลด: การกำหนดฟังก์ชั่นจำนวนมากด้วยชื่อเดียวกันและชนิดพารามิเตอร์ที่แตกต่างกันเช่น sqrt (float), sqrt (double) และ sqrt (complex) ในภาษาส่วนใหญ่ที่อนุญาตสิ่งนี้คอมไพเลอร์จะเลือกหนึ่งที่ถูกต้องโดยอัตโนมัติสำหรับประเภทของการโต้แย้งที่ถูกส่งผ่านมันดังนั้นนี่คือการรวบรวมความแตกต่างเวลา

  • วิธีเสมือนใน OOP: วิธีการเรียนสามารถมีการใช้งานที่หลากหลายที่เหมาะกับเฉพาะของคลาสย่อยนั้น แต่ละตัวถูกกล่าวเพื่อแทนที่การใช้งานที่กำหนดในคลาสฐาน ให้วัตถุที่อาจเป็นของคลาสพื้นฐานหรือคลาสย่อยใด ๆ ของมันการใช้งานที่ถูกต้องถูกเลือกในทันทีดังนั้นนี่คือความแตกต่างเวลาทำงาน

  • เทมเพลต: คุณสมบัติของภาษา OO บางภาษาที่ฟังก์ชันคลาส ฯลฯ สามารถกำหนดพารามิเตอร์ด้วยชนิด ตัวอย่างเช่นคุณสามารถกำหนดคลาสเทมเพลต "list" ทั่วไปแล้วยกตัวอย่างเป็น "list of integers", "list of strings", หรือแม้แต่ "list of list of strings" หรือสิ่งที่คล้ายกัน โดยทั่วไปคุณเขียนโค้ดหนึ่งครั้งสำหรับโครงสร้างข้อมูลประเภทองค์ประกอบเองและคอมไพเลอร์สร้างรุ่นของมันสำหรับประเภทองค์ประกอบต่างๆ


4

ความแตกต่างของคำมาจาก:

poly = มากมาย

morphism = ความสามารถในการเปลี่ยนแปลง

ในการเขียนโปรแกรม polymorphism เป็น "เทคนิค" ที่ช่วยให้คุณ "ดู" ที่วัตถุว่าเป็นสิ่งของมากกว่าหนึ่งประเภท ตัวอย่างเช่น

วัตถุนักเรียนยังเป็นวัตถุบุคคล หากคุณ "มอง" (เช่นส่ง) ที่นักเรียนคุณอาจขอรหัสนักศึกษาได้ คุณไม่สามารถทำสิ่งนั้นกับคนได้ใช่ไหม (บุคคลไม่จำเป็นต้องเป็นนักเรียนดังนั้นอาจไม่มีรหัสนักศึกษา) อย่างไรก็ตามบุคคลอาจมีชื่อ นักเรียนก็ทำเช่นกัน

บรรทัดล่าง "มอง" ที่วัตถุเดียวกันจาก "มุม" ที่แตกต่างกันสามารถให้มุมมอง "ที่แตกต่าง" (เช่นคุณสมบัติหรือวิธีการที่แตกต่างกัน)

ดังนั้นเทคนิคนี้ช่วยให้คุณสร้างสิ่งต่าง ๆ ที่สามารถ "มอง" จากมุมที่แตกต่างกัน

ทำไมเราถึงใช้พหุนาม สำหรับผู้เริ่มต้น ... สิ่งที่เป็นนามธรรม ณ จุดนี้มันควรมีข้อมูลเพียงพอ :)


3

ลองใช้การเปรียบเทียบกัน สำหรับบทละครเพลงที่ได้รับนักดนตรีทุกคนที่เล่นมันจะให้สัมผัสของเธอเองในการตีความ

นักดนตรีสามารถแยกออกได้ด้วยส่วนต่อประสานประเภทที่นักดนตรีสามารถเป็นคลาส abstrac ซึ่งกำหนดกฎการตีความระดับโลกบางส่วนและนักดนตรีทุกคนที่เล่นสามารถจำลองด้วยคลาสที่เป็นรูปธรรม

หากคุณเป็นผู้ฟังผลงานดนตรีคุณมีการอ้างอิงถึงสคริปต์เช่น Bach ของ 'Fuga และ Tocata' และนักดนตรีทุกคนที่ทำมันจะทำมัน polymorphicaly ในแบบของเธอเอง

นี่เป็นเพียงตัวอย่างของการออกแบบที่เป็นไปได้ (ใน Java):

public interface Musician {
  public void play(Work work);
}

public interface Work {
  public String getScript();
}

public class FugaAndToccata implements Work {
  public String getScript() {
    return Bach.getFugaAndToccataScript();
  }
}

public class AnnHalloway implements Musician {
  public void play(Work work) {
    // plays in her own style, strict, disciplined
    String script = work.getScript()
  }
}

public class VictorBorga implements Musician {
  public void play(Work work) {
    // goofing while playing with superb style
    String script = work.getScript()
  }
}

public class Listener {
  public void main(String[] args) {
    Musician musician;
    if (args!=null && args.length > 0 && args[0].equals("C")) {
      musician = new AnnHalloway();
    } else {
      musician = new TerryGilliam();
    }
    musician.play(new FugaAndToccata());
}

1
AnnHallowayและVictorBorgaรู้สึกว่าควรเป็นวัตถุมากกว่าคลาส - ตัวอย่างของคุณจะอ่านได้ดีขึ้นด้วยเช่น public class Pianist implements MusicianและvictorBorge = new Pianist();อื่น ๆ
Przemek D

3

ฉันได้ให้ภาพรวมระดับสูงของ polymorphism สำหรับคำถามอื่น:

ความแตกต่างใน c ++

หวังว่ามันจะช่วย สารสกัด ...

... มันช่วยให้เริ่มต้นจากการทดสอบอย่างง่ายสำหรับมันและนิยามของ [polymorphism] พิจารณารหัส:

Type1 x;
Type2 y;

f(x);
f(y);

นี่f()คือการดำเนินการบางอย่างและได้รับค่าxและyเป็นอินพุต ในการเป็น polymorphic f()จะต้องสามารถทำงานกับค่าที่แตกต่างกันอย่างน้อยสองประเภท (เช่นintและdouble) การค้นหาและดำเนินการโค้ดที่เหมาะสมกับประเภท

(ต่อที่polymorphism ใน c ++ )


3

ความแตกต่างคือความสามารถของวัตถุที่สามารถนำมาในหลายรูปแบบ ตัวอย่างเช่นในชั้นเรียนของมนุษย์มนุษย์สามารถแสดงออกได้หลายรูปแบบเมื่อเราพูดถึงความสัมพันธ์ EX: ผู้ชายคนหนึ่งเป็นพ่อของลูกชายของเขาและเขาเป็นสามีให้ภรรยาของเขาและเขาเป็นครูของนักเรียน


3

ความแตกต่างคือความสามารถของวัตถุที่ใช้ในหลายรูปแบบ การใช้ polymorphism ที่พบบ่อยที่สุดใน OOP เกิดขึ้นเมื่อมีการใช้การอ้างอิงระดับผู้ปกครองเพื่ออ้างถึงวัตถุคลาสลูก ในตัวอย่างนี้เขียนด้วยภาษาจาวาเรามียานพาหนะสามประเภท เราสร้างวัตถุสามแบบที่แตกต่างกันและพยายามใช้วิธีล้อของพวกเขา:

public class PolymorphismExample {

    public static abstract class Vehicle
    {
        public int wheels(){
            return 0;
        }
    }

    public static class Bike extends Vehicle
    {
        @Override
        public int wheels()
        {
            return 2;
        }
    }

    public static class Car extends Vehicle
    {
        @Override
        public int wheels()
        {
            return 4;
        }
    }

    public static class Truck extends Vehicle
    {
        @Override
        public int wheels()
        {
            return 18;
        }
    }

    public static void main(String[] args)
    {
        Vehicle bike = new Bike();
        Vehicle car = new Car();
        Vehicle truck = new Truck();

        System.out.println("Bike has "+bike.wheels()+" wheels");
        System.out.println("Car has "+car.wheels()+" wheels");
        System.out.println("Truck has "+truck.wheels()+" wheels");
    }

}

ผลลัพธ์คือ:

ผลลัพธ์

สำหรับข้อมูลเพิ่มเติมกรุณาเยี่ยมชมhttps://github.com/m-vahidalizadeh/java_advanced/blob/master/src/files/PolymorphismExample.java ฉันหวังว่ามันจะช่วย


ใช่ แต่คุณไม่ได้อธิบายว่าอะไรคือข้อดีของ polymorphism เห็นได้ชัดว่ามีรหัสที่สั้นลงซึ่งคุณจะลบคลาสยานพาหนะและมันจะยังคงใช้งานได้ (แน่นอนด้วยการประกาศวัตถุอื่น)
คอร์นีเลียส

ฉันไม่ได้อธิบายเพราะคนที่ถามคำถามไม่ได้ถามเกี่ยวกับผลประโยชน์ เขาถามว่า: "ความแตกต่างคืออะไรมีไว้เพื่ออะไรและใช้อย่างไร?" เกี่ยวกับรหัสถ้าคุณทำได้ดีกว่านี้โปรดโพสต์คำตอบของคุณ ดังนั้นชุมชนของเราสามารถใช้งานได้ ขอบคุณสำหรับความคิดเห็นของคุณ
Mohammad

ขออภัยไม่ต้องการที่จะฟังดูหยาบคายคนอื่นก็ไม่ได้อธิบายด้วย อย่างน้อยคุณก็ใส่ใจที่จะพิมพ์รหัส ยังไงก็ตามเขาถามว่ามันมีไว้ทำอะไร แต่ไม่มีตัวอย่างใดในหน้านี้ที่อธิบายว่ามันคืออะไร คุณเพียงแค่นำเสนอวิธีการที่ซับซ้อนเพื่อให้ได้ผลลัพธ์เช่นเดียวกับสิ่งนี้: s28.postimg.org/jq8vl6031/Poly.jpgและไม่มีใครสนใจที่จะอธิบายว่าทำไมคนเราต้องการใช้ polymorphism สิ่งที่ได้รับหรือวัตถุประสงค์ เสร็จแล้วถ้าไม่ได้ใช้? ทั้งหมดที่ฉันเห็นในหน้านี้เป็นข้อเสนอให้ปีนขึ้นไปที่อพาร์ทเมนต์ของคุณโดยใช้บันไดไม่ใช่ลิฟต์ ..
คอร์เนเลียส

.. โดยไม่สังเกตเห็นว่ามีเสาธงที่ใหญ่เกินไปที่จะติดตั้งลิฟต์ ผมไม่ทราบว่าวิธีการที่จะโพสต์รหัสดังนั้นฉันไม่สามารถจะให้ความช่วยเหลือมาก ...
คอร์นีเลีย

2

ความแตกต่างคือความสามารถของโปรแกรมเมอร์ในการเขียนวิธีการในชื่อเดียวกันที่ทำสิ่งต่าง ๆ สำหรับวัตถุประเภทต่าง ๆ ขึ้นอยู่กับความต้องการของวัตถุเหล่านั้น ตัวอย่างเช่นหากคุณกำลังพัฒนาคลาสที่เรียกว่าFractionและคลาสที่เรียกว่าComplexNumberทั้งสองนี้อาจมีวิธีการที่เรียกว่าdisplay()แต่แต่ละคนจะใช้วิธีการที่แตกต่างกัน ยกตัวอย่างเช่นใน PHP คุณอาจใช้มันในลักษณะนี้:

//  Class definitions

class Fraction
{
    public $numerator;
    public $denominator;

    public function __construct($n, $d)
    {
        //  In real life, you'd do some type checking, making sure $d != 0, etc.
        $this->numerator = $n;
        $this->denominator = $d;
    }

    public function display()
    {
        echo $this->numerator . '/' . $this->denominator;
    }
}

class ComplexNumber
{
    public $real;
    public $imaginary;

    public function __construct($a, $b)
    {
        $this->real = $a;
        $this->imaginary = $b;
    }

    public function display()
    {
        echo $this->real . '+' . $this->imaginary . 'i';
    }
}


//  Main program

$fraction = new Fraction(1, 2);
$complex = new ComplexNumber(1, 2);

echo 'This is a fraction: '
$fraction->display();
echo "\n";

echo 'This is a complex number: '
$complex->display();
echo "\n";

ขาออก:

This is a fraction: 1/2
This is a complex number: 1 + 2i

คำตอบอื่น ๆ ที่ดูเหมือนจะบ่งบอกว่ามีความหลากหลายที่ใช้ร่วมกับมรดกเท่านั้น ตัวอย่างเช่นบางทีFractionและComplexNumberทั้งคู่ใช้คลาสนามธรรมที่เรียกNumberว่ามีเมธอดdisplay()ซึ่ง Fraction และ ComplexNumber จะต้องดำเนินการทั้งคู่ แต่คุณไม่ต้องการรับมรดกเพื่อใช้ประโยชน์จากความหลากหลาย

อย่างน้อยในภาษาที่พิมพ์แบบไดนามิกเช่น PHP (ฉันไม่รู้เกี่ยวกับ C ++ หรือ Java), polymorphism ช่วยให้นักพัฒนาสามารถเรียกวิธีการโดยไม่จำเป็นต้องรู้ชนิดของวัตถุล่วงหน้าและเชื่อมั่นว่าการใช้วิธีการที่ถูกต้องจะ ถูกเรียก ตัวอย่างเช่นสมมติว่าผู้ใช้เลือกประเภทของการNumberสร้าง:

$userNumberChoice = $_GET['userNumberChoice'];

switch ($userNumberChoice) {
    case 'fraction':
        $userNumber = new Fraction(1, 2);
        break;
    case 'complex':
        $userNumber = new ComplexNumber(1, 2);
        break;
}

echo "The user's number is: ";
$userNumber->display();
echo "\n";

ในกรณีนี้display()จะเรียกวิธีการที่เหมาะสมแม้ว่าผู้พัฒนาจะไม่ทราบล่วงหน้าว่าผู้ใช้จะเลือกเศษส่วนหรือจำนวนเชิงซ้อน


2
นั่นไม่ใช่ความหลากหลาย นั่นเป็นสองคลาสที่มีวิธีการในชื่อเดียวกัน พวกเขาจะต้องมีการเชื่อมโยงโดยชั้นฐานหรืออินเตอร์เฟซที่เรียกว่า "แสดง" หรือสิ่งที่คล้ายกันและจากนั้นวิธีการอื่นจะเพียงแค่ดูแลว่าวัตถุที่เป็นประเภท "แสดง" มากกว่าซับซ้อนหรือเศษส่วน
Pod

ฉันคิดเสมอว่า polymorphism คือ "สองคลาสมีวิธีการของชื่อเดียวกัน" ในความเป็นจริงการอ้างอิง Stephan Kochan (ซึ่งฉันไร้ยางอายฉีกตัวอย่างเศษส่วน / ซับซ้อนนี้) "ความสามารถในการแบ่งปันชื่อวิธีการเดียวกันในคลาสที่แตกต่างกันเรียกว่า polymorphism" (จากProgramming_In_Objective-C ) เขาไม่พูดถึงความจำเป็นในการเชื่อมโยงคลาสผ่านคลาสพื้นฐาน บางทีมันอาจจะแตกต่างกันในภาษาที่ต่างกัน แต่ฉันก็ไม่รู้เหมือนกัน
Alex Basson

แม้จะมีการอ้างอิงแบบแข็งนี้มาจากหนังสือที่ตีพิมพ์ แต่ฉันก็ยังยืนยันว่ามันไม่ถูกต้อง โดยเฉพาะอย่างยิ่งเนื่องจากดูเหมือนว่าจะขัดแย้งกันทุกภาษาทำให้เกิดความไม่เชื่อเรื่องพระเจ้าของ polymorphism และในขณะที่ผลลัพธ์สุดท้ายนั้นเหมือนกับที่เห็นด้วย polymorphism ฉันจะโต้แย้งว่ามันเป็นการแทนที่การพิมพ์แบบไดนามิกที่ช่วยให้โปรแกรมเมอร์สามารถผลักดันให้การดำเนินการที่ถูกต้องของวิธีการอื่น ๆ ที่ถูกเรียกชื่อวิธีการที่คล้ายกัน
vipirtti

2

ในการเขียนโปรแกรมเชิงวัตถุ polymorphism หมายถึงการเขียนโปรแกรมภาษาของความสามารถในการกระบวนการวัตถุที่แตกต่างกันขึ้นอยู่กับชนิดข้อมูลหรือชั้นเรียนของตน โดยเฉพาะอย่างยิ่งมันเป็นความสามารถในการกำหนดวิธีการสำหรับชั้นเรียนที่ได้รับ


2

ความหลากหลายหมายถึงตัวอักษรหลายรูปร่าง (หรือหลายฟอร์ม): วัตถุจากคลาสที่ต่างกันและวิธีชื่อเดียวกัน แต่เวิร์กโฟลว์แตกต่างกัน ตัวอย่างง่ายๆคือ:

พิจารณาบุคคล X

เขาเป็นเพียงคนเดียว แต่ทำหน้าที่เป็นคนมากมาย คุณอาจถามว่า:

เขาเป็นลูกชายของแม่ เพื่อนกับเพื่อนของเขา น้องชายกับน้องสาวของเขา


2

ความหลากหลายใน OOP หมายถึงคลาสอาจมีประเภทที่แตกต่างกันการสืบทอดเป็นวิธีหนึ่งในการนำโพลิมอร์ฟิซึมมาใช้

ตัวอย่างเช่นShapeเป็นส่วนต่อประสานซึ่งมีชนิดย่อยSquare , Circle , Diamond ตอนนี้คุณมีวัตถุสแควร์แล้วคุณสามารถอัปโหลดสแควร์เป็นรูปร่างโดยอัตโนมัติเนื่องจากสแควร์เป็นรูปร่าง แต่เมื่อคุณพยายามที่จะลดขนาด Shape to Square คุณต้องทำการแคสต์ชนิดที่ชัดเจนเนื่องจากคุณไม่สามารถพูดได้ว่า Shape is Square อาจเป็น Circle ได้เช่นกัน ดังนั้นคุณต้องใช้มันด้วยรหัสเช่นSquare s = (Square)shapeถ้ารูปร่างเป็น Circle คุณจะได้รับjava.lang.ClassCastExceptionเพราะ Circle ไม่ใช่ Square


2

polymorphism:

การดำเนินการที่แตกต่างกันตามอินสแตนซ์ของคลาสไม่ใช่ประเภทของตัวแปรอ้างอิง

ตัวแปรอ้างอิงประเภทอินเตอร์เฟสสามารถอ้างถึงอินสแตนซ์ของคลาสใด ๆ ที่ใช้อินเทอร์เฟซนั้น


1

ความแตกต่างคือความสามารถในการใช้วัตถุในชั้นเรียนที่กำหนดซึ่งส่วนประกอบทั้งหมดที่ประกอบขึ้นเป็นวัตถุได้รับมรดกโดย subclasses ของชั้นที่กำหนด ซึ่งหมายความว่าเมื่อวัตถุนี้ถูกประกาศโดยคลาสแล้วคลาสย่อยทั้งหมดที่อยู่ด้านล่าง (และคลาสย่อยอื่น ๆ เป็นต้นจนกว่าคุณจะไปถึงคลาสย่อยที่ต่ำที่สุด / ต่ำสุด) สืบทอดวัตถุและส่วนประกอบ (เมคอัพ)

อย่าลืมว่าแต่ละคลาสจะต้องบันทึกไว้ในไฟล์แยกกัน

รหัสต่อไปนี้เป็นตัวอย่าง Polymorphism:

The SuperClass:

public class Parent {
    //Define things that all classes share
    String maidenName;
    String familyTree;

    //Give the top class a default method
    public void speak(){
         System.out.println("We are all Parents");
    }
}

พ่อ subclass:

public class Father extends Parent{
    //Can use maidenName and familyTree here
    String name="Joe";
    String called="dad";

    //Give the top class a default method
    public void speak(){
        System.out.println("I am "+name+", the father.");
    }
}

เด็กคลาสย่อยอื่น:

public class Child extends Father {
    //Can use maidenName, familyTree, called and name here

    //Give the top class a default method
    public void speak(){
        System.out.println("Hi "+called+". What are we going to do today?");
    }
}

วิธีการดำเนินการอ้างอิงระดับผู้ปกครองที่จะเริ่มต้น:

public class Parenting{
    public static void main(String[] args) {
        Parent parents = new Parent();
        Parent parent = new Father();
        Parent child = new Child();

        parents.speak();
        parent.speak();
        child.speak();
    }
}

โปรดทราบว่าแต่ละคลาสจะต้องประกาศในไฟล์ * .java แยกกัน รหัสควรรวบรวม นอกจากนี้โปรดสังเกตว่าคุณสามารถใช้นามสกุลเดิมและตระกูลได้อย่างต่อเนื่อง นั่นคือแนวคิดของความแตกต่าง แนวคิดของการสืบทอดยังถูกสำรวจที่นี่ซึ่งสามารถใช้คลาสหนึ่งคลาสหรือกำหนดคลาสย่อยเพิ่มเติมได้

หวังว่านี่จะช่วยและทำให้ชัดเจน ฉันจะโพสต์ผลลัพธ์เมื่อฉันพบคอมพิวเตอร์ที่ฉันสามารถใช้เพื่อตรวจสอบรหัส ขอบคุณสำหรับความอดทน!


2
โปรดทราบว่าเด็กทุกคนไม่ใช่ผู้ปกครองดังนั้นโครงสร้างนี้จึงผิด ชั้นบนสุดควรเป็นเด็ก (ถ้าคุณไม่ได้เพิ่งเริ่มต้นด้วย "บุคคล") ซึ่งจะเป็นจริงเสมอยกเว้นสำหรับอาดัม คุณสามารถตั้งค่า parent_id ของเขาเป็นโมฆะเนื่องจากผู้สร้างไม่สามารถกำหนดด้วยโครงสร้างของสติปัญญาของมนุษย์
Yehosef

1

ความแตกต่างช่วยให้กิจวัตรประจำวันเดียวกัน (ฟังก์ชั่นวิธีการ) เพื่อดำเนินการกับประเภทที่แตกต่างกัน

เนื่องจากคำตอบที่มีอยู่จำนวนมากกำลังสร้างความสับสนให้กับ subtyping ด้วย polymorphism ต่อไปนี้เป็นสามวิธี (รวมถึง subtyping) เพื่อสร้าง polymorphism

  • พารามิเตอร์หลากหลาย (ทั่วไป)อนุญาตให้รูทีนยอมรับพารามิเตอร์ประเภทหนึ่งหรือหลายพารามิเตอร์นอกเหนือจากพารามิเตอร์ปกติและเรียกใช้ตัวเองในประเภทเหล่านั้น
  • polymorphism ชนิดย่อยอนุญาตให้รูทีนดำเนินการกับชนิดย่อยของพารามิเตอร์
  • Ad Hoc polymorphismโดยทั่วไปจะใช้การทำงานหนักเกินปกติเพื่อให้เกิดพฤติกรรมที่หลากหลาย แต่สามารถอ้างถึงการใช้งาน polymorphism อื่น ๆ ได้เช่นกัน

ดูสิ่งนี้ด้วย:

http://wiki.c2.com/?CategoryPolymorphism

https://en.wikipedia.org/wiki/Polymorphism_(computer_science)


0

ในภาษาเชิงวัตถุความหลากหลายสามารถช่วยให้การรักษาและการจัดการชนิดข้อมูลที่แตกต่างกันผ่านอินเตอร์เฟซเดียวกัน ตัวอย่างเช่นพิจารณาการสืบทอดใน C ++: คลาส B มาจากคลาส A ตัวชี้ประเภท A * (ตัวชี้ไปยังคลาส A) อาจใช้เพื่อจัดการกับทั้งวัตถุของคลาส A และวัตถุของคลาส B


0

ความแตกต่างในเงื่อนไขการเข้ารหัสคือเมื่อวัตถุของคุณสามารถมีอยู่ได้หลายประเภทผ่านการสืบทอด ฯลฯ หากคุณสร้างคลาสที่ชื่อว่า "รูปร่าง" ซึ่งกำหนดจำนวนด้านของวัตถุของคุณคุณสามารถสร้างคลาสใหม่ที่สืบทอดเช่น "สแควร์" " เมื่อคุณสร้างอินสแตนซ์ของ "Square" คุณจะสามารถโยนมันไปข้างหน้าและส่งต่อจาก "Shape" ถึง "Square" ได้ตามต้องการ


0

ความแตกต่างทำให้คุณมีความสามารถในการสร้างโมดูลหนึ่งเรียกอีกโมดูลหนึ่งและยังมีจุดอ้างอิงเวลาคอมไพล์กับการไหลของการควบคุมแทนด้วยการไหลของการควบคุม

โดยใช้ polymorphism โมดูลระดับสูงไม่ได้ขึ้นอยู่กับโมดูลระดับต่ำ ทั้งสองขึ้นอยู่กับ abstractions สิ่งนี้ช่วยให้เราสามารถใช้หลักการผกผันของการพึ่งพา ( https://en.wikipedia.org/wiki/Dependency_inversion_principle )

นี่คือที่ฉันพบคำนิยามข้างต้น ประมาณ 50 นาทีในวิดีโอผู้สอนอธิบายข้างต้น https://www.youtube.com/watch?v=TMuno5RZNeE


0

ความแตกต่างคืออะไร?

ความแตกต่างคือความสามารถในการ:

  • เรียกใช้การดำเนินการในตัวอย่างของการเป็นชนิดพิเศษโดยเฉพาะการรู้ประเภททั่วไปในขณะที่เรียกวิธีการของชนิดพิเศษและไม่ว่าประเภททั่วไปที่: มันเป็นความแตกต่างแบบไดนามิก

  • กำหนดวิธีการหลายวิธีที่มีบันทึกชื่อ แต่มีพารามิเตอร์ differents: มันเป็นความแตกต่างแบบคงที่

ครั้งแรกหากนิยามทางประวัติศาสตร์และที่สำคัญที่สุด

polymorphism ใช้ทำอะไร?

อนุญาตให้สร้างความสอดคล้องอย่างยิ่งของลำดับชั้นของชั้นเรียนและทำสิ่งมหัศจรรย์บางอย่างเช่นการจัดการรายการของวัตถุประเภทต่าง ๆ โดยไม่ทราบประเภทของตน

การพิมพ์ที่แข็งแกร่งและอ่อนแอ

ตัวอย่าง

นี่คือรูปร่างบางส่วนเช่น Point, Line, สี่เหลี่ยมผืนผ้าและ Circle ที่มีการดำเนินการ Draw () โดยไม่ใช้พารามิเตอร์ใด ๆ หรืออย่างใดอย่างหนึ่งเพื่อตั้งค่าการหมดเวลาเพื่อลบ

public class Shape
{
 public virtual void Draw()
 {
   DoNothing();
 }
 public virtual void Draw(int timeout)
 {
   DoNothing();
 }
}

public class Point : Shape
{
 int X, Y;
 public override void Draw()
 {
   DrawThePoint();
 }
}

public class Line : Point
{
 int Xend, Yend;
 public override Draw()
 {
   DrawTheLine();
 }
}

public class Rectangle : Line
{
 public override Draw()
 {
   DrawTheRectangle();
 }
}

var shapes = new List<Shape> { new Point(0,0), new Line(0,0,10,10), new rectangle(50,50,100,100) };

foreach ( var shape in shapes )
  shape.Draw();

ต่อไปนี้เป็นคลาส Shape และ Shape.Draw () วิธีการควรถูกทำเครื่องหมายเป็นนามธรรม

พวกเขาไม่ได้เพื่อให้เข้าใจ

ชี้แจง

หากไม่มี polymorphism โดยใช้ abstract-virtual-override ขณะแยกวิเคราะห์รูปร่างมันเป็นเพียงวิธี Spahe.Draw () ที่เรียกว่า CLR โดยไม่รู้วิธีที่จะเรียก ดังนั้นมันจึงเรียกเมธอดของชนิดที่เราดำเนินการและนี่คือประเภทคือรูปร่างเนื่องจากการประกาศรายการ ดังนั้นโค้ดจึงไม่ทำอะไรเลย

ด้วย polymorphism CLR สามารถอนุมานชนิดของวัตถุที่แท้จริงที่เรากระทำโดยใช้สิ่งที่เรียกว่าตารางเสมือน ดังนั้นจึงเรียกวิธีการที่ดีและที่นี่เรียก Shape.Draw () ถ้า Shape is Point เรียก Point.Draw () ดังนั้นรหัสวาดรูปร่าง

อ่านเพิ่มเติม

C # - ความหลากหลาย (ระดับ 1)

ความแตกต่างใน Java (ระดับ 2)

ความหลากหลาย (คู่มือการเขียนโปรแกรม C #)

ตารางวิธีการเสมือน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.