typescript - การแมปวัตถุไปยังคุณสมบัติของมันเองเป็นสิ่งปฏิบัติที่ไม่ดีหรือไม่?
ฉันมักจะพบว่าตัวเองกำลังส่งต่อวัตถุที่มีรหัสหรือชื่อที่ระบุวัตถุนั้น แต่ก็เป็นสมบัติของวัตถุนั้นด้วย ตัวอย่างเช่น:
type ExampleItemName = string;
interface ExampleItem {
name: ExampleItemName ;
value: number;
}
ฉันมักจะต้องสร้างรายการของสิ่งเหล่านี้อยู่บ่อยครั้ง และฉันพบว่ามันสะดวกที่จะสามารถเข้าถึงสิ่งเหล่านี้ได้จาก name ของพวกมัน โครงสร้างข้อมูลที่สมเหตุสมผลที่สุดที่ฉันเห็นสำหรับสิ่งนี้คือ Map ตัวอย่างเช่น:
type ExampleItemList = Map<ExampleItemName, ExampleItem>;
นี่สะดวกและง่ายต่อการใช้งาน เพราะฉันสามารถเข้าถึงรายการใด ๆ ตาม name ด้วย Map.get แต่ฉันก็สามารถวนซ้ำทั้งรายการได้อย่างง่ายดายโดยใช้ for...of ด้วยเช่นกัน
อย่างไรก็ตาม สิ่งนี้รู้สึกไม่ถูกต้องสำหรับฉันเพราะข้อมูล name ถูกทำซ้ำ - มันมีทั้งในคีย์และในค่าของแมป หาก name ของ ExampleItem เปลี่ยนไป คีย์ที่สอดคล้องกันในแมปจะไม่เปลี่ยน ดังนั้นมันจึงรู้สึกเปราะบาง
นี่เป็นวิธีปฏิบัติที่ไม่ดีหรือไม่? ถ้าใช่ มีวิธีที่ดีกว่าในการทำให้ได้ฟังก์ชันที่ฉันต้องการหรือไม่?
คำตอบ #1
นี่ไม่ใช่การปฏิบัติที่ไม่ดีโดยตรง แต่มีเงื่อนไขบางประการที่ต้องปฏิบัติตาม มิฉะนั้นคุณอาจเจอปัญหาเหมือนปัญหาที่คุณกล่าวถึงเกี่ยวกับค่าที่คุณใช้เป็นคีย์แล้วเปลี่ยนแปลง รูปแบบนี้มักถูกเรียกว่าเป็นการทำคีย์ข้อมูลของคุณ การปฏิบัติที่ดีที่สุดคือใช้ค่าที่คุณรู้ว่าจะไม่เปลี่ยนแปลง เช่น ID เป็นคีย์ เนื่องจากพจนานุกรมมักช่วยลดค่าใช้จ่ายของฟังก์ชันการค้นหาที่มีราคาแพง จึงจำเป็นในหลายสถานการณ์ แต่ตามที่ฉันกล่าวไว้และคุณก็ชี้ให้เห็น คุณต้องเลือกใช้คีย์โดยใช้ค่าที่ไม่เปลี่ยนแปลงและไม่ซ้ำกัน หรือคุณจะต้องอัปเดตและจัดการค่าซ้ำทุกครั้งที่ใช้พจนานุกรม การเลือกวิธีแก้ปัญหาที่เหมาะสมนั้นขึ้นอยู่กับสถานการณ์ของคุณ
นอกจากนี้ ไลบรารีอย่าง lodash ยังมีฟังก์ชันที่สร้างขึ้นมาแล้ว (ซึ่งคุณสามารถเขียนเองได้ง่าย ๆ) ที่นำเข้าข้อมูลและจัดเรียงคีย์ให้คุณ คุณยังจะพบว่าแนวคิดเหล่านี้ถูกใช้กันอย่างแพร่หลายในภาษาอื่น ๆ แม้ว่าพวกมันจะมีชื่อเรียกต่างกัน (python: dictionary, Java: hashMap, เป็นต้น)
คำตอบ #2
ถ้ามันไม่สร้างความไม่สะดวกมากเกินไป คุณสามารถลองสร้างโครงสร้างรายการของคุณเองที่ตรงกับกรณีการใช้งานของคุณ เช่น รายการต่อไปนี้
class NameMap<K, V extends { name: K }> {
private items: Set<V> = new Set();
Add(value: V) { this.items.add(value); }
Get(key: K) {
for(let e of this.items.values()) if(e.name == key) return e;
return undefined;
}
[Symbol.iterator]() { return this.items[Symbol.iterator](); };
}
type ExampleItemList = NameMap<ExampleItemName, ExampleItem>;
