ตัวแก้ไขไดอะแกรมคลาส Mermaid
ไดอะแกรมคลาสแสดงชนิดข้อมูลและความสัมพันธ์ระหว่างกัน ว่าอะไรบรรจุอะไร อะไรสืบทอดจากอะไร และอะไรขึ้นกับอะไร เหมาะเมื่อแก่นของเรื่องคือรูปร่างของโค้ด เช่น แบบจำลองโดเมน อินเทอร์เฟซสำหรับส่วนขยาย หรือต้นไม้การสืบทอด ถ้าคุณอยากแสดงสิ่งที่เกิดขึ้นตอนทำงานจริง ไม่ใช่ว่าชนิดข้อมูลประกอบกันอย่างไร ให้ใช้ไดอะแกรมลำดับ
แบบจำลองโดเมนของการชำระเงิน
ความสัมพันธ์สามแบบในไดอะแกรมเดียว คือองค์ประกอบสำหรับส่วนที่อยู่ไม่ได้เมื่อไม่มีทั้งหมด การสืบทอดสำหรับลำดับชั้นของวิธีชำระเงิน และการเชื่อมโยงธรรมดาที่มีพหุภาพ สังเกตว่าตัวระบุของทุกคลาสเป็นอักษรละติน ส่วนชื่อที่แสดงอยู่ในวงเล็บเหลี่ยมเป็นภาษาไทย วิธีนี้ทำให้ตัวระบุถูกต้องและยังคงเห็นภาษาไทยบนจอ
classDiagram
class Order["คำสั่งซื้อ"] {
+String เลขที่
+OrderStatus สถานะ
+Money ยอดรวม()
+void เพิ่มรายการ(Product สินค้า, int จำนวน)
}
class OrderLine["รายการสินค้า"] {
+Product สินค้า
+int จำนวน
+Money มูลค่า()
}
class PaymentMethod["วิธีชำระเงิน"] {
<<abstract>>
+อนุมัติ(Money ยอดเงิน) bool
}
class QrPayment["พร้อมเพย์"] {
+String เลขอ้างอิง
+อนุมัติ(Money ยอดเงิน) bool
}
class CardPayment["บัตรเครดิต"] {
+String สี่ตัวท้าย
+อนุมัติ(Money ยอดเงิน) bool
}
class CashOnDelivery["เก็บเงินปลายทาง"] {
+Money ค่าธรรมเนียม
+อนุมัติ(Money ยอดเงิน) bool
}
Order "1" *-- "1..*" OrderLine : ประกอบด้วย
Order --> PaymentMethod : ชำระด้วย
PaymentMethod <|-- QrPayment
PaymentMethod <|-- CardPayment
PaymentMethod <|-- CashOnDeliveryตัวอย่างพร้อมคำอธิบาย
1. คลาสเดียว
`+` คือสาธารณะ `-` คือส่วนตัว และ `#` คือป้องกัน สมาชิกที่มีวงเล็บจะถูกวาดเป็นเมท็อด ถ้าไม่มีวงเล็บก็เป็นฟิลด์
classDiagram
class User["ผู้ใช้"] {
+String อีเมล
-String รหัสผ่านที่แฮชแล้ว
+bool ตรวจสอบ(String ค่าที่กรอก)
}2. การสืบทอดและอินเทอร์เฟซ
`<|--` คือการสืบทอด อ่านว่า «ตัวทางขวาขยายตัวทางซ้าย» ส่วนคำกำกับ `<<interface>>` เป็นเพียงป้าย ไม่ใช่พฤติกรรม แต่มันคือสิ่งที่ตัดสินว่าไดอะแกรมอ่านง่ายหรือไม่
classDiagram
class Repository["รีพอซิทอรี"] {
<<interface>>
+ค้นหา(String รหัส) Entity
+บันทึก(Entity รายการ) void
}
class PostgresRepository["รีพอซิทอรี Postgres"] {
-Connection การเชื่อมต่อ
+ค้นหา(String รหัส) Entity
+บันทึก(Entity รายการ) void
}
class MemoryRepository["รีพอซิทอรีในหน่วยความจำ"] {
-Map ที่เก็บ
+ค้นหา(String รหัส) Entity
+บันทึก(Entity รายการ) void
}
Repository <|.. PostgresRepository
Repository <|.. MemoryRepository3. องค์ประกอบเทียบกับการรวมกลุ่ม
ความต่างอยู่ที่อายุการอยู่รอด ข้าวหลามตัดทึบ (`*--`) หมายความว่าส่วนย่อยหายไปพร้อมทั้งหมด ลบใบกำกับภาษีแล้วรายการในนั้นก็หายไปด้วย ส่วนข้าวหลามตัดโปร่ง (`o--`) หมายความว่าส่วนย่อยอยู่ได้ด้วยตัวเอง
classDiagram
class Invoice["ใบกำกับภาษี"] {
+String เลขที่
}
class InvoiceLine["รายการในใบกำกับ"] {
+String รายละเอียด
}
class Customer["ลูกค้า"] {
+String ชื่อบริษัท
}
Invoice "1" *-- "1..*" InvoiceLine : ประกอบด้วย
Customer "1" o-- "0..*" Invoice : ได้รับ4. ชนิดข้อมูลแบบเจเนอริก
เครื่องหมายตัวหนอนใช้กำหนดพารามิเตอร์ของชนิดข้อมูล เช่น `Repository~User~` การซ้อนกันก็ทำได้ ซึ่งบางครั้งจำเป็นและไม่ค่อยเป็นความคิดที่ดีนัก
classDiagram
class Repository~T~ {
+ค้นหา(String รหัส) T
+ทั้งหมด() List~T~
}
class Cache~K, V~ {
+ดึง(K คีย์) V
+ใส่(K คีย์, V ค่า) void
}
class UserRepository["รีพอซิทอรีผู้ใช้"] {
+ค้นหาด้วยอีเมล(String อีเมล) User
}
Repository~User~ <|-- UserRepository5. หมายเหตุและทิศทาง
`direction LR` จัดวางไดอะแกรมจากซ้ายไปขวา ซึ่งมักเข้ากับต้นไม้การสืบทอดได้ดีกว่าการจัดวางตั้งต้น ส่วนหมายเหตุคือที่ที่เหมาะสำหรับข้อจำกัดที่ใส่ลงในกล่องคลาสไม่ได้
classDiagram
direction LR
class EventStore["ที่เก็บเหตุการณ์"] {
+เพิ่ม(Event เหตุการณ์) void
+เล่นซ้ำ(String สาย) List~Event~
}
class Snapshot["ภาพสแนปช็อต"] {
+int รุ่น
+byte[] เนื้อหา
}
EventStore --> Snapshot : เขียนทุก 100 เหตุการณ์
note for EventStore "เพิ่มได้อย่างเดียว เหตุการณ์จะไม่ถูกแก้ไขหรือลบ"สรุปไวยากรณ์ไดอะแกรมคลาส
ลูกศรความสัมพันธ์คุ้มค่าที่จะจำ เพราะมันคือสิ่งที่แยกไดอะแกรมคลาสออกจากภาพกล่องต่อเส้น และมันอ่านจากหัวลูกศรย้อนกลับ ซึ่งทำให้เข้าใจผิดอยู่นาน
| ไวยากรณ์ | ความหมาย |
|---|---|
| classDiagram | เปิดไดอะแกรม แยกตัวพิมพ์ใหญ่เล็ก |
| class Name["ชื่อ"] { ... } | ตัวระบุอักษรละตินพร้อมชื่อภาษาไทยที่แสดงบนจอ สำหรับภาษาไทยควรใช้รูปแบบนี้เสมอ |
| class Name { ... } | คลาสพร้อมสมาชิก วงเล็บปีกกาปิดอยู่บรรทัดของตัวเอง |
| +สมาชิก | สาธารณะ |
| -สมาชิก | ส่วนตัว |
| #สมาชิก | ป้องกัน |
| +เมท็อด(Type arg) ReturnType | เมท็อด สิ่งที่ทำให้เป็นเมท็อดคือวงเล็บ |
| <<interface>> / <<abstract>> | สเตอริโอไทป์ เขียนบรรทัดแรกภายในคลาส |
| A <|-- B | การสืบทอด B ขยาย A |
| A <|.. B | การนำไปใช้จริง B ทำตามอินเทอร์เฟซ A |
| A *-- B | องค์ประกอบ B อยู่ไม่ได้เมื่อไม่มี A |
| A o-- B | การรวมกลุ่ม B อยู่ได้โดยไม่มี A |
| A --> B | การเชื่อมโยงที่มีทิศทาง |
| A ..> B | การพึ่งพา A ใช้ B แต่ไม่ได้เก็บไว้ |
| A "1" --> "0..*" B : ป้ายกำกับ | พหุภาพทั้งสองฝั่งพร้อมป้ายกำกับความสัมพันธ์ |
| class Repo~T~ | พารามิเตอร์ชนิดข้อมูลแบบเจเนอริก |
| note for A "ข้อความ" | หมายเหตุที่ผูกกับคลาสหนึ่ง |
| direction LR | เปลี่ยนทิศทางการจัดวาง |
ข้อผิดพลาดที่ทำให้ไดอะแกรมคลาสพัง
สร้างซ้ำบน Mermaid 11.12.2 ไดอะแกรมคลาสเป็นหนึ่งในประเภทที่ผ่อนปรนกว่าเพื่อน ครึ่งหนึ่งของข้อผิดพลาดเหล่านี้จึงแสดงผลออกมาเงียบ ๆ และยื่นภาพที่ผิดให้คุณ
สิ่งที่คุณเห็น
Lexical error on line N. Unrecognized text.
ทำไม
ชื่อคลาสเขียนด้วยอักษรไทย ชื่อคลาสก็เป็นตัวระบุเช่นกัน และเหมือนตัวระบุโหนดของผังงาน อักษรไทยถูกปฏิเสธที่นี่ วัดแล้ว `class คำสั่งซื้อ` ล้มด้วยข้อผิดพลาดนี้
วิธีแก้
ให้ตัวระบุเป็นอักษรละตินแล้วใส่ชื่อที่แสดงไว้ในวงเล็บเหลี่ยม เช่น `class Order["คำสั่งซื้อ"]` ทดสอบแล้วว่าใช้ได้ ตัวระบุภายในยังเป็น `Order` และบนจอแสดงว่า `คำสั่งซื้อ` ส่วนชื่อสมาชิกยังเป็นภาษาไทยได้ เพราะไม่ใช่ตัวระบุ
classDiagram
class คำสั่งซื้อ {
+String เลขที่
}classDiagram
class Order["คำสั่งซื้อ"] {
+String เลขที่
}สิ่งที่คุณเห็น
Parse error ที่ลงท้ายด้วย: got 'EOF_IN_STRUCT'
ทำไม
ตัวคลาสเปิดด้วย `{` แล้วไม่เคยปิด คราวนี้ชื่อโทเคนช่วยได้จริง มันบอกว่าไฟล์จบลงขณะที่เรายังอยู่ภายในคลาส
วิธีแก้
ปิดวงเล็บปีกกาบนบรรทัดของตัวเอง
classDiagram
class Order["คำสั่งซื้อ"] {
+String เลขที่classDiagram
class Order["คำสั่งซื้อ"] {
+String เลขที่
}สิ่งที่คุณเห็น
Parse error ที่ลงท้ายด้วย: got 'ANNOTATION_END'
ทำไม
ใช้ลูกศรของไดอะแกรมลำดับในไดอะแกรมคลาส `->>` ไม่มีความหมายที่นี่ และตัวแจงเดินเข้าไปลึกพอที่จะคืนชื่อโทเคนที่ชวนให้เข้าใจผิด
วิธีแก้
ใช้ความสัมพันธ์ของไดอะแกรมคลาส คือ `-->` สำหรับการเชื่อมโยง `<|--` สำหรับการสืบทอด และ `*--` สำหรับองค์ประกอบ
classDiagram
Order ->> CustomerclassDiagram
Order --> Customer : เป็นของสิ่งที่คุณเห็น
ลูกศรชี้ไปคนละทางกับที่คุณตั้งใจ
ทำไม
ลูกศรความสัมพันธ์อ่านจากหัวลูกศรย้อนกลับ `A <|-- B` หมายความว่า B สืบทอดจาก A ไม่ใช่ตรงกันข้าม เขียนกลับด้านก็ยังแสดงผลได้ เพียงแต่ตอนนี้มันอ้างว่าคลาสฐานไปขยายคลาสลูกของตัวเอง
วิธีแก้
อ่านว่า «ปลายที่อยู่ไกลขยายปลายที่มีหัวลูกศร» แล้ววางคลาสแม่ไว้ทางซ้ายของ `<|--`
classDiagram
CardPayment <|-- PaymentMethodclassDiagram
PaymentMethod <|-- CardPaymentสิ่งที่คุณเห็น
มีฟิลด์โผล่มาในที่ที่คุณคาดว่าจะเป็นเมท็อด
ทำไม
วงเล็บคือสิ่งเดียวที่แยกเมท็อดออกจากฟิลด์ `+บันทึก` คือฟิลด์ชื่อบันทึก ส่วน `+บันทึก()` คือเมท็อด ทั้งสองรูปแบบถูกต้อง จึงไม่มีอะไรเตือน
วิธีแก้
เติมวงเล็บเข้าไป แล้วตามด้วยชนิดข้อมูลที่คืนค่าถ้าอยากให้เห็น
classDiagram
class Repo {
+บันทึก
+ค้นหา
}classDiagram
class Repo {
+บันทึก(Entity รายการ) void
+ค้นหา(String รหัส) Entity
}สิ่งที่คุณเห็น
องค์ประกอบกับการรวมกลุ่มดูเหมือนกันเมื่อมองผ่าน ๆ แต่บอกตรงกันข้าม
ทำไม
`*--` กับ `o--` ต่างกันอักขระเดียว และทั้งคู่เข้ารหัสความต่างเชิงความหมายที่มีอยู่จริง คือส่วนย่อยอยู่รอดหลังทั้งหมดหายไปหรือไม่ การใช้ผิดตัวให้ไดอะแกรมที่ถูกต้องตามรูปแบบแต่เป็นเท็จต่อโดเมนของคุณ
วิธีแก้
ข้าวหลามตัดทึบ `*--` เมื่อลบตัวแม่แล้วตัวลูกหายไปด้วย ส่วนโปร่ง `o--` เมื่อไม่หาย
classDiagram
Order o-- OrderLine : ประกอบด้วยclassDiagram
Order *-- OrderLine : ประกอบด้วยหมายเหตุเรื่องการแสดงผล
วัดบน Mermaid 11.12.2 ซึ่งเป็นรุ่นที่เว็บนี้ใช้
ชื่อในวงเล็บเหลี่ยมคือทางออกที่แท้จริงของไดอะแกรมคลาสภาษาไทย
นี่คือสิ่งที่มีประโยชน์ที่สุดในหน้านี้ `class คำสั่งซื้อ` ล้มเพราะชื่อคลาสเป็นตัวระบุและอักษรไทยไม่ผ่านตรงนั้น แต่ `class Order["คำสั่งซื้อ"]` ทดสอบแล้วและใช้ได้ ตัวระบุที่ออกมาคือ `classId-Order` ขณะที่บนจอแสดงคำว่า `คำสั่งซื้อ` และที่ดีกว่านั้นคือความสัมพันธ์ระหว่างคลาสที่ตั้งชื่อแบบนี้ก็ทำงานได้ตามปกติ ทดสอบ `<|--` ระหว่างคลาสสองตัวที่ใช้วงเล็บเหลี่ยมแล้วแสดงผลถูกต้อง แปลว่าไดอะแกรมคลาสภาษาไทยไม่จำเป็นต้องโชว์อักษรละตินให้ผู้อ่านเห็นเลย
ชื่อสมาชิกไม่ใช่ตัวระบุ จึงเป็นภาษาไทยได้
ข้อจำกัดอยู่ที่ชื่อคลาสเท่านั้น ชื่อสมาชิก ชื่อพารามิเตอร์ และชื่อชนิดข้อมูลที่คืนค่า ถูกปฏิบัติเหมือนป้ายกำกับ ทั้ง `+String เลขที่` และ `+Money ยอดรวม()` แสดงผลตรงตามที่เขียน และวงเล็บก็ยังทำหน้าที่เปลี่ยนให้เป็นเมท็อดได้เหมือนกับชื่อภาษาอังกฤษ ผลคือข้อความส่วนใหญ่ในไดอะแกรมเป็นภาษาไทยได้ เหลือเพียงตัวระบุภายในของคลาสที่เป็นอักษรละติน
มันโตขึ้นด้านบนเร็วกว่าทุกประเภทที่นี่
วัดจากคลาสที่มีสมาชิกละสองตัวและผูกกันด้วยการสืบทอด สามคลาสให้ viewBox ราว 176×548 ส่วนสี่สิบคลาสให้ 180×7726 คือราว 194 พิกเซลต่อคลาส ซึ่งเป็นอัตราที่ชันที่สุดในหกประเภทของเว็บนี้ ไดอะแกรมสี่สิบคลาสสูงเกินเจ็ดพันพิกเซลและใช้เป็นภาพเดียวไม่ได้ `direction LR` ช่วยได้ แต่เกินราวสิบห้าคลาสไปแล้ว ทางออกที่ซื่อตรงคือแบ่งไดอะแกรมตามขอบเขตของโดเมน
จำนวนสมาชิกแทบไม่มีผลต่อความกว้าง
ความกว้างถูกกำหนดโดยลายเซ็นที่ยาวที่สุดของสมาชิกตัวเดียว ไม่ใช่จำนวนสมาชิก คลาสที่มีฟิลด์สั้น ๆ ยี่สิบตัวไม่ได้กว้างกว่าคลาสที่มีสามตัว พูดอีกอย่างคือใจกว้างกับสมาชิกได้ แต่ต้องตระหนี่กับคลาส ซึ่งตรงข้ามกับสัญชาตญาณพอดี
ป้ายกำกับเป็น HTML การส่งออก PNG จึงวาดใหม่
ป้ายกำกับของคลาสถูกวาดภายใน `<foreignObject>` ในไฟล์ SVG และเบราว์เซอร์ปฏิเสธที่จะแปลงมันเป็นภาพแรสเตอร์บนแคนวาส การส่งออก PNG ของเว็บนี้เคยล้มเหลวอย่างเงียบ ๆ และคืนไฟล์ SVG ตอนนี้มันวาดไดอะแกรมใหม่ด้วยป้ายกำกับข้อความ SVG ล้วนก่อน ไฟล์ PNG จึงออกมาถูกต้องและเต็มขนาด โดยการจัดวางตัวอักษรต่างจากบนจอเล็กน้อย
เมื่อใดควรใช้ไดอะแกรมประเภทอื่น
ถ้าคุณกำลังทำเอกสารของฐานข้อมูล ไม่ใช่ระบบชนิดข้อมูล ให้ใช้ไดอะแกรม ER ความต่างนี้สำคัญ เพราะไดอะแกรมคลาสจำลองพฤติกรรมและการสืบทอดซึ่งตารางไม่มี ส่วนไดอะแกรม ER จำลองคีย์และพหุภาพได้เรียบร้อย ซึ่งไดอะแกรมคลาสผ่านไปแบบผิวเผิน
ถ้าไดอะแกรมส่วนใหญ่เป็นกล่องที่ต่อกันด้วย `-->` และไม่มีสมาชิกเลย แสดงว่าคุณกำลังวาดสถาปัตยกรรม ไม่ใช่ไดอะแกรมคลาส ผังงานที่มีกลุ่มย่อยจะดูดีกว่าและอ้างสิ่งต่าง ๆ น้อยกว่า
และถ้ารายชื่อคลาสเกิดขึ้นจากโค้ด ลองพิจารณาว่าไดอะแกรมควรเกิดจากที่เดียวกันหรือไม่ ไดอะแกรมคลาสที่ดูแลด้วยมือสำหรับฐานโค้ดที่เปลี่ยนทุกสัปดาห์จะกลายเป็นเท็จภายในหนึ่งเดือน และไดอะแกรมที่ผิดมีราคาแพงกว่าการไม่มีไดอะแกรมเลย
ไดอะแกรมประเภทอื่น
เขียนโดย Dominik Malsch · อัปเดตล่าสุด: