Dart ชื่อ Constructor, Static Method และ Factory Constructor

รับรหัสต่อไปนี้:

const jsonString = '{"myString":"Hello"}';
final jsonMap = jsonDecode(jsonString);

final myObject = MyClass.fromJson(jsonMap);

มีกี่วิธีในการสร้างออบเจ็กต์ใหม่โดยใช้ไวยากรณ์นี้:

MyClass.fromJson(jsonMap)

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


person Suragch    schedule 07.08.2020    source แหล่งที่มา


คำตอบ (2)


หากต้องการสร้างอินสแตนซ์ใหม่ของวัตถุโดยใช้ไวยากรณ์ต่อไปนี้:

MyClass.fromJson(jsonMap)

เพื่อใช้กับรหัสต่อไปนี้:

// import 'dart:convert';

const jsonString = '{"myString":"Hello"}';
final jsonMap = jsonDecode(jsonString);

final myObject = MyClass.fromJson(jsonMap);

อย่างน้อยก็มีวิธีการดังต่อไปนี้ (พร้อมหมายเหตุเสริมเกี่ยวกับคุณลักษณะของแต่ละรายการ):

คอนสตรัคเตอร์กำเนิด

class MyClass {
  MyClass(this.myString);
  final String myString;

  MyClass.fromJson(Map<String, dynamic> json) : this(json['myString']);
}

ตัวสร้างกำเนิดมีสองประเภท: มีชื่อและไม่มีชื่อ MyClass.fromJson() เป็นตัวสร้างที่มีชื่อในขณะที่ MyClass() เป็นตัวสร้างที่ไม่มีชื่อ หลักการต่อไปนี้ใช้กับตัวสร้างแบบกำเนิด:

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

ผู้สร้างโรงงาน

class MyClass {
  MyClass(this.myString);
  final String myString;

  factory MyClass.fromJson(Map<String, dynamic> json) {
    return MyClass(json['myString']);
  }
}
  • ตัวสร้างโรงงานอาจส่งคืนชนิดย่อยของคลาส
  • ตัวสร้างโรงงานสามารถใช้สร้างซิงเกิลตันได้
  • ตัวสร้างโรงงานสามารถไม่มีชื่อเหมือนกับตัวสร้างแบบกำเนิด
  • ตัวสร้างโรงงานสามารถเป็น const ได้ แต่เฉพาะเมื่อเปลี่ยนเส้นทางเท่านั้น

วิธีแบบคงที่

class MyClass {
  MyClass(this.myString);
  final String myString;

  static MyClass fromJson(Map<String, dynamic> json) {
    return MyClass(json['myString']);
  }
}
  • วิธีการคงที่อาจส่งคืนอะไรก็ได้ รวมถึงอนาคตด้วย
  • วิธีการคงที่สามารถใช้เพื่อสร้างซิงเกิลตันได้
  • วิธีการแบบคงที่สามารถใช้เป็นวิธีฉีกขาดได้

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

person Suragch    schedule 07.08.2020
comment
คุณหมายถึงอะไรกับ Named constructors may only use the initializer list to set final properties.? แม้จะมีคอนสตรัคเตอร์ที่มีชื่อเช่น MyClass.named(this.myString) คุณก็สามารถเริ่มต้นคุณสมบัติสุดท้ายได้ นอกจากนี้ คุณสามารถสร้างซิงเกิลตันโดยใช้คอนสตรัคเตอร์ factory เช่น ที่นี่ - person Mattia; 07.08.2020
comment
@ Mattia ขอบคุณที่ชี้ให้เห็น ความหมายของฉันคือไม่สามารถตั้งค่าคุณสมบัติสุดท้ายในเนื้อหาคอนสตรัคเตอร์ที่มีชื่อได้ แต่ฉันไม่เจาะจงเพียงพอ ฉันอัปเดตคำตอบของฉันสำหรับอันนั้น ส่วนซิงเกิลตันนั้นผมพูดถึงอันนั้นไปแล้ว (อย่างไรก็ตาม การมีมันภายใต้วิธีสแตติกก็อาจทำให้ดูเหมือนว่านั่นเป็นวิธีเดียวที่จะสร้างซิงเกิลตันได้ จริงไหม?) - person Suragch; 07.08.2020
comment
@lrn ฉันรู้สึกว่าคอนสตรัคเตอร์แบบกำเนิดคือตัวที่ไม่มีชื่อนั่นคือตัวที่ใช้ชื่อคลาสเพียงอย่างเดียว นั่นไม่เป็นความจริงเหรอ? - person Suragch; 08.08.2020
comment
@lrn ฉันถามคำถามโดยละเอียดเพิ่มเติมที่นี่: stackoverflow.com/questions/63313102/ - person Suragch; 08.08.2020
comment
ตอบไปแล้วแต่ไม่ มันไม่จริง ความเป็นกำเนิดหรือโรงงานนั้นตั้งฉากกับการตั้งชื่อหรือไม่ก็ตาม ตัวสร้างโรงงานนั้นนำหน้าด้วย factory ส่วนที่เหลือเป็นแบบกำเนิด จะระบุชื่อหรือไม่ระบุก็ได้ - person lrn; 09.08.2020

นอกจาก @suragch คำตอบโดยละเอียดแล้ว ฉันต้องการให้สัญลักษณ์แสดงหัวข้อย่อยที่แสดง factory constructor เป็นตัวเลือกที่ดีที่สุดสำหรับสถานการณ์ข้างต้น (สำหรับวิธี fromJson())

  • เมื่อใช้ Factory Constructor คุณไม่จำเป็นต้องเริ่มต้นตัวแปรอินสแตนซ์ของคลาสนั้น (แต่เมื่อคุณใช้คอนสตรัคเตอร์แบบกำเนิด จำเป็นต้องเริ่มต้นตัวแปรอินสแตนซ์สุดท้ายทั้งหมด)

  • ตัวสร้างโรงงานสามารถส่งคืนวัตถุที่มีอยู่ได้ เช่น: - เมื่อใช้แพ็คเกจ json_seriazible วิธี fromJson() จะส่งคืนออบเจ็กต์ที่มีอยู่ (สร้างไว้ก่อนหน้านี้) ดังนั้นเราจึงสามารถใช้ได้เฉพาะตัวสร้างโรงงานกับแพ็คเกจนี้เท่านั้น

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

  • ตรวจสอบให้แน่ใจว่ามีเพียงอินสแตนซ์เดียวของคลาสที่สร้างขึ้น (รูปแบบซิงเกิลตัน) (วัตถุมีราคาแพง ดังนั้น fromJson จึงจำเป็นต้องมีรูปแบบซิงเกิลตัน)

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

person TDM    schedule 21.04.2021
comment
สำหรับประเด็นที่ 4 ของคุณ ฉันถือว่ามัน สามารถ ใช้เพื่อสร้างซิงเกิลตันได้ อย่างไรก็ตาม ตัวสร้างโรงงานยังสามารถใช้เพื่อสร้างวัตถุใหม่ได้ทุกครั้ง - person Suragch; 21.04.2021
comment
@Suragch [หากตัวสร้างโรงงานส่งคืนวัตถุที่มีอยู่ =› รูปแบบซิงเกิลตัน True (จุดที่ 4 ถูกต้อง)] [แต่ถ้าตัวสร้างโรงงานส่งคืนการเรียกตัวสร้าง (สร้างอินสแตนซ์ใหม่) =› รูปแบบซิงเกิลตันเท็จ (จุดที่ 4 ไม่ถูกต้อง) ฉัน คิดว่านี่คือประเด็นที่คุณพยายามจะพูด ฉันถูกไหม? - person TDM; 21.04.2021
comment
ใช่ที่ถูกต้อง. - person Suragch; 22.04.2021