ลำดับชั้นแบบขนาน - เหมือนกันบางส่วนแตกต่างกันเล็กน้อย


12

มีคำถามที่คล้ายกันอยู่สองสามข้อ 1 ,2 ,3 ,4แต่ดูเหมือนว่าไม่ใช่ในกรณีของคำถามนี้และการแก้ปัญหาก็ดูดีที่สุด

นี่เป็นคำถามทั่วไปของ OOP โดยสมมติว่ามีหลายรูปแบบชื่อสามัญและมิกซ์อินมีอยู่ ภาษาจริงที่ใช้คือ OOP Javascript (Typescript) แต่เป็นปัญหาเดียวกันใน Java หรือ C ++

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

3 ลำดับชั้นของคลาสแบบขนานคอลัมน์กลางแสดงส่วนทั่วไปคอลัมน์ด้านซ้ายคือลำดับชั้นของผืนผ้าใบและคอลัมน์ด้านขวาแสดงลำดับชั้น SVG

นี้สำหรับวัตถุประสงค์ในการประกอบการอธิบายเท่านั้น ; มันไม่ใช่แผนภาพคลาสที่แท้จริง หากต้องการอ่าน:

  • สิ่งใดก็ตามในลำดับชั้นทั่วไป (กลาง) จะแชร์กันระหว่างทั้ง Canvas (ซ้าย) และ SVG (ขวา) ด้วยการแบ่งปันฉันหมายถึงทั้งอินเทอร์เฟซและการใช้งาน
  • สิ่งใดก็ตามที่อยู่บนคอลัมน์ซ้ายหรือขวาหมายถึงพฤติกรรม (วิธีการและสมาชิก) เฉพาะสำหรับลำดับชั้นนั้น ตัวอย่างเช่น:
    • ทั้งลำดับชั้นซ้ายและขวาใช้กลไกการตรวจสอบความถูกต้องเดียวกันแสดงเป็นวิธีการเดียว ( Viewee.validate()) ในลำดับชั้นทั่วไป
    • paint()เพียงลำดับชั้นของผ้าใบมีวิธีการ วิธีนี้เรียกวิธีการทาสีบนเด็กทุกคน
    • ลำดับชั้น SVG จำเป็นต้องแทนที่addChild()วิธีการCompositeแต่ไม่ได้เป็นกรณีที่มีลำดับชั้นของผืนผ้าใบ
  • โครงสร้างจากลำดับชั้นทั้งสองไม่สามารถผสมกันได้ โรงงานทำให้มั่นใจได้ว่า

โซลูชัน I - Tease Apart Inheritance

Tease Apart Inheritance ของ Fowler ดูเหมือนจะไม่ทำงานที่นี่เพราะมีความคลาดเคลื่อนระหว่างสองแนว

โซลูชัน II - มิกซ์อิน

นี่เป็นสิ่งเดียวที่ฉันสามารถนึกได้ ทั้งสองลำดับชั้นมีการพัฒนาแยกจากกัน แต่ในแต่ละระดับชั้นเรียนผสมในชั้นเรียนทั่วไปซึ่งไม่ได้เป็นส่วนหนึ่งของลำดับชั้นของชั้นเรียน ไม่ใช้structuralส้อมจะมีลักษณะดังนี้:

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

โปรดทราบว่าแต่ละคอลัมน์จะอยู่ในเนมสเปซของตนเองดังนั้นชื่อคลาสจะไม่ขัดแย้งกัน

คำถาม

ทุกคนสามารถเห็นข้อบกพร่องด้วยวิธีนี้ได้หรือไม่? ทุกคนคิดวิธีที่ดีกว่าได้ไหม


ภาคผนวก

นี่คือตัวอย่างโค้ดที่จะใช้ เนมสเปซsvgอาจถูกแทนที่ด้วยcanvas:

var iView        = document.getElementById( 'view' ),
    iKandinsky   = new svg.Kandinsky(),
    iEpigone     = new svg.Epigone(),
    iTonyBlair   = new svg.TonyBlair( iView, iKandinsky ),
    iLayer       = new svg.Layer(),
    iZoomer      = new svg.Zoomer(),
    iFace        = new svg.Rectangle( new Rect( 20, 20, 100, 60) ),
    iEyeL        = new svg.Rectangle( new Rect( 20, 20, 20, 20) ),
    iEyeR        = new svg.Rectangle( new Rect( 60, 20, 20, 20) );

iKandinsky.setContext( iTonyBlair.canvas.getContext( '2d' ) );
iEpigone.setContext( iTonyBlair.canvas.getContext( '2d' ) );

iFace.addChildren( iEyeL, iEyeR );
iZoomer.setZoom( new Point( 2, 2 ) );
iZoomer.addChild( iFace );
iLayer.addChild( iZoomer );
iTonyBlair.setContent( iLayer );

โดยพื้นฐานแล้วในไคลเอนต์รันไทม์ประกอบด้วยลำดับชั้นอินสแตนซ์ของคลาสย่อยของ Viewee ชอบมาก:

รูปภาพแสดงลำดับชั้นของวัตถุเช่นเลเยอร์, ​​rect, scroller เป็นต้น

สมมติว่าผู้ชมเหล่านี้ทั้งหมดมาจากลำดับชั้นของภาพวาดพวกเขาจะแสดงผลโดยการข้ามผ่านลำดับชั้นที่สามารถเรียกดูได้paint()ในแต่ละวิว หากมาจากลำดับชั้น svg ผู้ดูจะรู้วิธีเพิ่มตัวเองใน DOM แต่ไม่มีการpaint()แวะผ่าน



อาจลองใช้รูปแบบการออกแบบมัณฑนากรเต็มรูปแบบ (Erich Gamma et als, Design Patterns)
— Zon

ผู้ชมคืออะไร "ขนาน" หมายถึงคำนามอะไร (ตรงข้ามกับคำคุณศัพท์)?
— Tulains Córdova

คุณมีหลายมรดกหรือไม่
— Tulains Córdova

คลาส Canvas หรือ SVG มีสถานะหรือข้อมูลเพิ่มเติมที่ไม่เหมือนกันหรือไม่? คุณใช้คลาสอย่างไร คุณสามารถแสดงรหัสตัวอย่างบางส่วนที่แสดงว่า hiearchies เหล่านี้สามารถใช้งานได้อย่างไร
— ร่าเริง

คำตอบ:


5

วิธีที่สองแยกอินเตอร์เฟสที่ดีกว่าตามหลักการแยกอินเตอร์เฟส

อย่างไรก็ตามฉันจะเพิ่มส่วนต่อประสาน Paintable

ฉันจะเปลี่ยนชื่อด้วย ไม่จำเป็นต้องสร้างความสับสน:

// common

public interface IComposite {
    public void addChild(Composite e);
}

public interface IViewee extends IComposite{
    public void validate();
    public List<IBound> getAbsoluteBouns();
}

public interface IVisual {
    public List<IBound> getBounds();
}

public interface IRec {
}

public interface IPaintable {
    public void paint();
}

// canvas

public interface ICanvasViewee extends IViewee, IPaintable {
}

public interface ICanvasVisual extends IViewee, IVisual {
}

public interface ICanvasRect extends ICanvasVisual, IRec {
}


// SVG

public interface ISVGViewee extends IViewee {
    public void element();
}

public interface ISVGVisual extends IVisual, ISVGViewee {
}

public interface ISVGRect extends ISVGVisual, IRect {
}

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

ไม่ downvoter แต่อินเตอร์เฟซ IMHO ชี้แจงไม่ได้เป็นรูปแบบที่ดี
— dagnelies

@arnaud คุณหมายถึงอะไร "อินเตอร์เฟซเอ็กซ์โปเนนเชียล"
— Tulains Córdova

@ user61852 ... เอาล่ะสมมติว่ามันมีอินเตอร์เฟสมากมาย "exponential" เป็นคำที่ผิดจริง ๆ มันเหมือนกับ "multiplicative" ในแง่ที่ว่าถ้าคุณมี "facets" (คอมโพสิต, ภาพ, ทาสีได้ ... ) และ "องค์ประกอบ" เพิ่มเติม (canvas, svg ... ) คุณจะต้องจบลงด้วยอินเตอร์เฟสมากมาย
— dagnelies

@arnaud คุณมีประเด็น แต่อย่างน้อยก็มีการออกแบบที่ยืดหยุ่นล่วงหน้าและฝันร้ายที่สืบทอดมาจาก OP จะแก้ไขได้เมื่อคุณไม่รู้สึกว่าถูกบังคับให้ต้องขยายเวลา คุณขยายคลาสบางคลาสถ้าคุณต้องการและไม่ถูกบังคับโดยลำดับชั้นที่วางแผนไว้
— Tulains Córdova

3

นี่เป็นคำถามทั่วไปของ OOP โดยสมมติว่ามีหลายรูปแบบชื่อสามัญและมิกซ์อินมีอยู่ ภาษาจริงที่ใช้คือ OOP Javascript (Typescript) แต่เป็นปัญหาเดียวกันใน Java หรือ C ++

ที่จริงไม่เป็นความจริงเลย typescript มีข้อได้เปรียบที่สำคัญกว่า Java - กล่าวคือการพิมพ์โครงสร้าง คุณสามารถทำสิ่งที่คล้ายกันใน C ++ ด้วยเทมเพลตที่พิมพ์เป็ด แต่มันเป็นความพยายามมากขึ้น

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

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

เพียงแค่กำหนดแต่ละคลาสและลืมเกี่ยวกับการพิมพ์โครงสร้างอินเตอร์เฟสจะดูแล

ตัวอย่างเช่น:

class SVGViewee {
    validate() { /* stuff */ }
    addChild(svg: SVG) { /* stuff */ }
}
class CanvasViewee {
    validate() { /* stuff */ }
    paint() { /* stuff */ }
}
interface SVG {
    addChild: { (svg: SVG): void };
}
f(viewee: { validate: { (): boolean }; }) {
    viewee.validate();
}
g(svg: SVG) {
    svg.addChild(svg);
}
h(canvas: { paint: { (): void }; }) {
    canvas.paint();
}
f(SVGViewee());
f(CanvasViewee());
g(SVGViewee());
h(CanvasViewee());

นี่คือ typescript ที่ถูกต้องตามกฎหมายโดยสิ้นเชิง ขอให้สังเกตว่าฟังก์ชั่นการบริโภคไม่ทราบหรือให้อึเพียงครั้งเดียวเกี่ยวกับคลาสพื้นฐานหรืออินเทอร์เฟซที่ใช้ในคำจำกัดความของคลาส

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


ดูเหมือนว่าจะมีแนวโน้ม แต่ฉันไม่เข้าใจข้อเสนอจริง ๆ (ขออภัยอาจมีอคติ OOP มากเกินไป) บางทีคุณสามารถแบ่งปันตัวอย่างรหัสได้ไหม? ตัวอย่างเช่นทั้งsvg.Vieweeและcanvas.Vieweeต้องการvalidate()วิธี (การใช้งานซึ่งเหมือนกันทั้งคู่); ดังนั้นsvg.Vieweeเพียงอย่างเดียวจึงต้องแทนที่addChild ()ในขณะที่เฉพาะcanvas.Vieweeต้องการโปรแกรมระบายสี () (ซึ่งเรียกใช้โปรแกรมระบายสี ()สำหรับเด็กทุกคน - ซึ่งเป็นสมาชิกของคลาสคอมโพสิตฐาน) ดังนั้นฉันจึงไม่สามารถมองเห็นสิ่งนี้ด้วยการพิมพ์เชิงโครงสร้าง
— Izhaki

คุณกำลังพิจารณาทุกสิ่งที่ไม่สำคัญในกรณีนี้
— DeadMG

ดังนั้นฉันอาจไม่ได้รับคำตอบเลย คงจะดีถ้าคุณทำอย่างละเอียด
— Izhaki

ฉันแก้ไข บรรทัดล่างคือว่าคลาสพื้นฐานนั้นไม่เกี่ยวข้องอย่างแน่นอนและไม่มีใครใส่ใจเกี่ยวกับพวกเขา พวกเขามีรายละเอียดการใช้งานเท่านั้น
— DeadMG

1
ตกลง. นี่เป็นการเริ่มต้นที่สมเหตุสมผล A) ฉันรู้ว่าการพิมพ์เป็ดคืออะไร B) ฉันไม่แน่ใจว่าเพราะเหตุใดอินเทอร์เฟซจึงเป็นศูนย์กลางในคำตอบนี้ - การแบ่งคลาสเพื่อประโยชน์ในการแบ่งปันพฤติกรรมทั่วไปคุณสามารถละเว้นอินเทอร์เฟซได้อย่างปลอดภัยในตอนนี้ C) พูดในตัวอย่างที่คุณมีSVGViewee.addChild()แต่CanvasVieweeต้องการคุณสมบัติเดียวกันทั้งหมด ดูเหมือนว่าจะสมเหตุสมผลสำหรับฉันว่าทั้งคู่มาจากคอมโพสิต?
— Izhaki

3

ภาพรวมอย่างรวดเร็ว

โซลูชันที่ 3: รูปแบบการออกแบบซอฟต์แวร์ "Parallel Class Hierarchy" เป็นเพื่อนของคุณ

คำตอบที่ยาวนาน

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

มีการจัดการกับแนวคิดเดียวกันหลายครั้งมักจะอยู่ในลำดับชั้นการควบคุม

หลังจากนั้นไม่นานฉันก็ลงเอยด้วยการแก้ปัญหาที่เหมือนกันกว่านักพัฒนาอื่น ๆ ซึ่งบางครั้งเรียกว่ารูปแบบการออกแบบ "ลำดับชั้นคู่ขนาน" หรือรูปแบบการออกแบบ "ลำดับคู่คู่"

(1) คุณเคยแบ่งคลาสเดี่ยวเป็นลำดับชั้นของชั้นเดียวหรือไม่?

(2) คุณเคยแบ่งชั้นหนึ่งเป็นหลายชั้นโดยไม่มีลำดับชั้นหรือไม่?

หากคุณได้ใช้วิธีแก้ไขปัญหาก่อนหน้านี้แยกจากกันเป็นวิธีแก้ปัญหาบางอย่าง

แต่ถ้าเรารวมสองโซลูชั่นนี้พร้อมกันล่ะ

รวมเข้าด้วยกันและคุณจะได้รับ "รูปแบบการออกแบบ" นี้

การดำเนินงาน

ตอนนี้มาปรับใช้รูปแบบการออกแบบซอฟต์แวร์ "Parallel Class Hierarchy" กับกรณีของคุณ

ขณะนี้คุณมีลำดับชั้นของคลาสอย่างน้อย 2 คลาสที่คล้ายกันมากมีการเชื่อมโยงหรือ purpouse ที่คล้ายกันมีคุณสมบัติหรือวิธีการที่คล้ายกัน

คุณต้องการหลีกเลี่ยงการมีรหัสซ้ำหรือสมาชิก ("ความสอดคล้อง") แต่คุณไม่สามารถรวมคลาสนี้เข้าเป็นหนึ่งเดียวได้โดยตรงเนื่องจากความแตกต่างระหว่างพวกเขา

ดังนั้นลำดับชั้นของคุณคล้ายกันมากกับรูปนี้ แต่ยังมีมากกว่าหนึ่ง:

................................................
...............+----------------+...............
...............|     Common::   |...............
...............|    Composite   |...............
...............+----------------+...............
...............|      ...       |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
...............+-------+--------+...............
...............|     Common::   |...............
...............|     Viewee     |...............
...............+----------------+...............
...............|      ...       |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..|     Common::   |........|     Common::   |..
..|     Visual     |........|   Structural   |..
..+----------------+........+----------------+..
..|      ...       |........|      ...       |..
..+----------------+........+----------------+..
................................................

Figure 1

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

โปรดทราบว่าการแก้ปัญหานี้มีความซับซ้อนเพราะคุณกำลังจัดการกับหลายลำดับชั้นแล้วจึงเป็นสถานการณ์ที่ซับซ้อน

1 คลาสรูต

ในแต่ละลำดับชั้นจะมีคลาส "root" ที่ใช้ร่วมกัน

ในกรณีของคุณมีคลาส "คอมโพสิต" อิสระสำหรับแต่ละลำดับชั้นที่สามารถมีคุณสมบัติที่คล้ายกันและวิธีการที่คล้ายกันบางอย่าง

สมาชิกบางคนสามารถรวมกันได้บางส่วนของสมาชิกเหล่านั้นไม่สามารถรวมได้

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

ในรูปที่ 2 คุณสามารถเห็นไดอะแกรมสำหรับคลาสนี้ซึ่งแต่ละคลาสเก็บไว้ที่เนมสเปซ

สมาชิกจะถูกละไว้โดยขณะนี้

................................................
...............+-------+--------+...............
...............|     Common::   |...............
...............|    Composite   |...............
...............+----------------+...............
...............|      ...       |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..|     Canvas::   |........|      SVG::     |..
..|    Composite   |........|    Composite   |..
..+----------------+........+----------------+..
..|      ...       |........|      ...       |..
..+----------------+........+----------------+..
................................................

Figure 2

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

จากนั้นให้เพิ่มสมาชิกที่เหมือนกันสามารถย้ายไปที่ซูเปอร์คลาสและสมาชิกที่แตกต่างกันไปยังคลาสพื้นฐานแต่ละคลาส

และอย่างที่คุณทราบแล้ววิธีการ "เสมือน" หรือ "โอเวอร์โหลด" ถูกกำหนดไว้ในคลาสฐาน แต่แทนที่ในคลาสย่อย เหมือนรูปที่ 3

................................................
.............+--------------------+.............
.............|       Common::     |.............
.............|      Composite     |.............
.............+--------------------+.............
.............| [+] void AddChild()|.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..|     Canvas::   |........|      SVG::     |..
..|    Composite   |........|    Composite   |..
..+----------------+........+----------------+..
..|      ...       |........|      ...       |..
..+----------------+........+----------------+..
................................................

Figure 3

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

2 คลาสย่อย

ลองย้อนกลับไปที่แผนภาพแรก แต่ละคลาส "Composite" มีคลาสย่อย "Viewee" ในแต่ละลำดับชั้น

กระบวนการซ้ำสำหรับแต่ละชั้นเรียน หมายเหตุกว่ารูปที่ 4 คลาส "Common :: Viewee" สืบทอดมาจาก "Common :: Composite" แต่เพื่อความเรียบง่ายคลาส "Common :: Composite" จะถูกละเว้นจากแผนภาพ

................................................
.............+--------------------+.............
.............|       Common::     |.............
.............|       Viewee       |.............
.............+--------------------+.............
.............|        ...         |.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..|     Canvas::   |........|      SVG::     |..
..|     Viewee     |........|     Viewee     |..
..+----------------+........+----------------+..
..|      ...       |........|      ...       |..
..+----------------+........+----------------+..
................................................

Figure 4

คุณจะสังเกตได้ว่า "Canvas :: Viewee" และ "SVG :: Viewee" ไม่ได้สืบทอดมาจาก "Composite" ที่เกี่ยวข้องอีกต่อไป แต่มาจาก Common "View :: Viewee ทั่วไป" แทน

คุณสามารถเพิ่มสมาชิกได้ทันที

......................................................
.........+------------------------------+.............
.........|            Common::          |.............
.........|            Viewee            |.............
.........+------------------------------+.............
.........| [+] bool Validate()          |.............
.........| [+] Rect GetAbsoluteBounds() |.............
.........+-------------+----------------+.............
.......................|..............................
.......................^..............................
....................../.\.............................
.....................+-+-+............................
.......................|..............................
..........+------------+----------------+.............
..........|.............................|.............
..+-------+---------+........+----------+----------+..
..|      Canvas::   |........|         SVG::       |..
..|      Viewee     |........|        Viewee       |..
..+-----------------+........+---------------------+..
..|                 |........| [+] Viewee Element  |..
..+-----------------+........+---------------------+..
..| [+] void Paint()|........| [+] void addChild() |..
..+-----------------+........+---------------------+..
......................................................

Figure 5

3 ทำซ้ำกระบวนการ

กระบวนการจะดำเนินต่อไปสำหรับแต่ละคลาส "Canvas :: Visual" จะไม่สืบทอดจาก "Canvas :: Viewee" จาก "Commons :: Visual", "Canvas :: Structural" จะไม่สืบทอดมาจาก "Canvas :: Viewee ", buit จาก" Commons :: Structural "และอื่น ๆ

4 แผนภาพลำดับชั้น 3D

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

ลำดับชั้นคลาสอิสระดั้งเดิมของคุณซึ่งมีลักษณะคล้ายกับนี้ (รูปที่ 6):

.................................................
..+-----------------+.......+-----------------+..
..|      Common::   |.......|       SVG::     |..
..|     Composite   |.......|     Composite   |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..|      Common::   |.......|       SVG::     |..
..|      Viewee     |.......|      Viewee     |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..|      Common::   |.......|       SVG::     |..
..|      Visual     |.......|      Visual     |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..|      Common::   |.......|       SVG::     |..
..|       Rect      |.......|       Rect      |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+-----------------+.......+-----------------+..
.................................................

Figure 6

โปรดทราบว่าบางคลาสจะถูกตัดออกและลำดับชั้น "Canvas" ทั้งหมดจะถูกตัดออกเพื่อให้ง่ายขึ้น

ลำดับชั้นของคลาสรวมขั้นสุดท้ายอาจเป็นสิ่งที่คล้ายกับสิ่งนี้:

.................................................
..+-----------------+.../+..+-----------------+..
..|      Common::   +--<.+--+       SVG::     |..
..|     Composite   |...\+..|     Composite   |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..|      Common::   +--<.+--+       SVG::     |..
..|      Viewee     |...\+..|      Viewee     |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..|      Common::   +--<.+--+       SVG::     |..
..|      Visual     |...\+..|      Visual     |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..|      Common::   +--<.+--+       SVG::     |..
..|       Rect      |...\+..|       Rect      |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+-----------------+.......+-----------------+..
.................................................
Figure 7

โปรดทราบว่าบางคลาสจะถูกละไว้และคลาส "Canvas" ทั้งหมดจะถูกตัดออกเพื่อให้ง่าย แต่จะคล้ายกับคลาส "SVG"

คลาส "Common" สามารถแสดงเป็นเลเยอร์เดียวของไดอะแกรม 3 มิติคลาส "SVG" ในอีกชั้นหนึ่งและคลาส "Canvas" ในเลเยอร์ที่สาม

ตรวจสอบว่าแต่ละเลเยอร์เกี่ยวข้องกับชั้นแรกซึ่งแต่ละชั้นมีคลาสพาเรนต์ของลำดับชั้น "ทั่วไป"

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

สรุป

ในฐานะที่เป็นโซลูชั่นการเขียนโปรแกรมใด ๆ อย่ารีบเร่งในการเพิ่มประสิทธิภาพการเพิ่มประสิทธิภาพเป็นสิ่งสำคัญมาก แต่การเพิ่มประสิทธิภาพที่ไม่ดีอาจกลายเป็นปัญหาใหญ่กว่าปัญหาเดิม

ฉันไม่แนะนำให้ใช้ "โซลูชัน 1" หรือ "โซลูชัน 2" อย่างใดอย่างหนึ่ง

ใน "โซลูชัน 1" ไม่ได้ใช้เนื่องจากต้องใช้การสืบทอดในแต่ละกรณี

"Solution 2", "Mixins" อาจถูกนำไปใช้ แต่หลังจากออกแบบคลาสและลำดับชั้น

Mixins เป็นทางเลือกสำหรับการสืบทอดตามอินเตอร์เฟสหรือการสืบทอดหลายคลาสที่อิงกับคลาส

โซลูชัน 3 ที่เสนอของฉันบางครั้งเรียกว่ารูปแบบการออกแบบ "ลำดับชั้นแบบขนาน" หรือรูปแบบการออกแบบ "ลำดับชั้นคู่"

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

อีกสิ่งที่ขาดหายไป ในการแก้ปัญหาก่อนหน้าของคุณปัญหาหลักไม่ได้เกิดขึ้นว่าจะใช้ "mixins" หรือ "interfaces" แต่เพื่อปรับแต่งก่อนรูปแบบของชั้นเรียนของคุณและใช้คุณลักษณะภาษาการเขียนโปรแกรมที่มีอยู่ในภายหลัง


ขอบคุณสำหรับคำตอบอย่างละเอียด ผมคิดว่าผมเข้าใจว่ามันไม่เป็นไรเพื่อให้ฉันถามนี้และทุกลูกหลานต้องมีวิธีการที่เรียกว่าcanvas.viewee paint()ทั้งcommonหรือsvgเรียนจำเป็นต้องใช้มัน แต่ในโซลูชันของคุณมีลำดับชั้นcommonไม่เหมือนcanvasหรือsvgเหมือนในโซลูชันของฉัน 2 ดังนั้นpaint()จะสิ้นสุดลงอย่างไรในคลาสย่อยทั้งหมดcanvas.vieweeหากไม่มีการสืบทอด
— Izhaki

@Izhaki ขออภัยหากมีข้อบกพร่องเล็กน้อยในคำตอบของฉัน แล้วpaint()ควรจะย้ายหรือประกาศใน "ผ้าใบ :: viewee" แนวคิดรูปแบบทั่วไปยังคงอยู่ แต่สมาชิกบางคนอาจต้องย้ายหรือเปลี่ยนแปลง
— umlcat

ตกลงดังนั้นวิธีการที่ไม่ย่อยได้รับมันถ้าไม่มีใครมาจากจากcanvas::viewee?
— Izhaki

คุณใช้เครื่องมือในการสร้างงานศิลปะ ASCII ของคุณหรือไม่? (ฉันไม่แน่ใจว่าจุดช่วยจริงสำหรับสิ่งที่คุ้มค่า)
— Aaron Hall

1

ในบทความเรื่องรูปแบบการออกแบบสำหรับการซื้อขายกับคู่มรดกลำดับชั้นใน C ++ , ลุงบ๊อบนำเสนอวิธีการแก้ปัญหาที่เรียกว่าStairway to Heaven มันระบุไว้เจตนา:

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

และแผนภาพให้:

แผนผังคลาสที่มีโครงสร้างการสืบทอดสองขนานซึ่งแต่ละคลาสทางด้านขวานั้นมีอยู่ในคลาสเดียวกันทางด้านซ้าย  ลำดับชั้นด้านซ้ายยังยึดตามการสืบทอดเสมือนอย่างสมบูรณ์

แม้ว่าในโซลูชันที่ 2 จะไม่มีการสืบทอดเสมือนจริง แต่เป็นไปตามรูปแบบของStairway to Heaven ดังนั้นวิธีที่ 2 ดูเหมือนจะสมเหตุสมผลกับปัญหานี้

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