ภาษา OO สามารถใช้แทนภาษาระดับต่ำในบางครั้งเพื่อเชื่อมต่อโดยตรงกับเครื่อง C ++ แน่นอน แต่สำหรับ C # ก็มีอะแดปเตอร์และเช่นนั้น แม้ว่าการเขียนรหัสเพื่อควบคุมชิ้นส่วนเครื่องจักรกลและมีการควบคุมหน่วยความจำนาทีจะดีที่สุดใกล้เคียงกับระดับต่ำที่สุด แต่ถ้าคำถามนี้เกี่ยวข้องกับซอฟต์แวร์เชิงวัตถุในปัจจุบันเช่น Line Of Business, เว็บแอพพลิเคชั่น, IOT, Web Services และแอปพลิเคชั่นที่ใช้งานมากที่สุด ...
ตอบถ้ามี
ผู้อ่านอาจลองทำงานกับ Service-Oriented Architecture (SOA) นั่นคือ DDD, N-Layered, N-Tiered, Hexagonal อะไรก็ตาม ฉันไม่ได้เห็นแอปพลิเคชันธุรกิจขนาดใหญ่ใช้ "OO" แบบดั้งเดิม "อย่างมีประสิทธิภาพ (Active-Record หรือ Rich-Models) อย่างที่อธิบายไว้ในยุค 70 และ 80 ในทศวรรษที่ผ่านมา + (ดูหมายเหตุ 1)
ความผิดไม่ใช่ของ OP แต่มีปัญหาสองสามข้อกับคำถาม
ตัวอย่างที่คุณให้ไว้เป็นเพียงการแสดงให้เห็นถึงความหลากหลายมันไม่ได้เป็นรหัสการผลิต บางครั้งตัวอย่างที่เหมือนกันอย่างแท้จริง
ใน FP และ SOA ข้อมูลจะถูกแยกออกจาก Business Logic นั่นคือข้อมูลและลอจิกไม่ทำงานร่วมกัน ลอจิกเข้าสู่บริการและ Data (Domain Models) ไม่มีพฤติกรรม Polymorphic (ดูหมายเหตุ 2)
บริการและฟังก์ชั่นสามารถ Polymorphic ใน FP คุณมักส่งผ่านฟังก์ชันเป็นพารามิเตอร์ไปยังฟังก์ชันอื่นแทนค่า คุณสามารถทำสิ่งเดียวกันใน OO ภาษาที่มีประเภทเช่น Callable หรือ Func แต่มันไม่ทำงานอาละวาด (ดูหมายเหตุ 3) ใน FP และ SOA โมเดลของคุณไม่ใช่ Polymorphic เฉพาะบริการ / ฟังก์ชันของคุณ (ดูหมายเหตุ 4)
มีกรณีที่ไม่ดีของการเข้ารหัสในตัวอย่างนั้น ฉันไม่เพียง แต่พูดถึงสตริงสีแดง "หมาเห่า" ฉันยังพูดถึง CatModel และ DogModel ด้วย จะเกิดอะไรขึ้นเมื่อคุณต้องการเพิ่มแกะ คุณต้องเข้าไปในรหัสของคุณและสร้างรหัสใหม่? ทำไม? ในรหัสการผลิตฉันอยากเห็นเพียง AnimalModel ที่มีคุณสมบัติของมัน ที่เลวร้ายที่สุด AmphibianModel และ FowlModel หากคุณสมบัติและการจัดการแตกต่างกันมาก
นี่คือสิ่งที่ฉันคาดว่าจะเห็นในภาษา "OO" ปัจจุบัน:
public class Animal
{
public int AnimalID { get; set; }
public int LegCount { get; set; }
public string Name { get; set; }
public string WhatISay { get; set; }
}
public class AnimalService : IManageAnimals
{
private IPersistAnimals _animalRepo;
public AnimalService(IPersistAnimals animalRepo) { _animalRepo = animalRepo; }
public List<Animal> GetAnimals() => _animalRepo.GetAnimals();
public string WhatDoISay(Animal animal)
{
if (!string.IsNullOrWhiteSpace(animal.WhatISay))
return animal.WhatISay;
return _animalRepo.GetAnimalNoise(animal.AnimalID);
}
}
คุณย้ายจาก Classes ใน OO ไปยัง Function Programming ได้อย่างไร อย่างที่คนอื่นพูด คุณทำได้ แต่คุณทำไม่ได้จริงๆ ประเด็นข้างต้นคือการแสดงให้เห็นว่าคุณไม่ควรใช้คลาส (ในความหมายดั้งเดิมของโลก) เมื่อใช้งาน Java และ C # เมื่อคุณเขียนโค้ดในสถาปัตยกรรมที่มุ่งเน้นการบริการ (DDD, Layered, Tiered, Hexagonal, อะไรก็ตาม) คุณจะเข้าใกล้ฟังก์ชั่นการทำงานเพียงขั้นตอนเดียวเนื่องจากคุณแยกข้อมูล (โมเดลโดเมน) ออกจากฟังก์ชันตรรกะ (Services)
ภาษา OO ใกล้ FP
คุณอาจต้องใช้เวลาเพิ่มอีกนิดและแยก SOA Services ออกเป็นสองประเภท
Class Class แบบเลือกได้ 1 : บริการปรับใช้อินเตอร์เฟสทั่วไปสำหรับจุดเข้าใช้งาน สิ่งเหล่านี้จะเป็นจุดเข้าใช้งาน "ไม่บริสุทธิ์" ซึ่งสามารถเรียกใช้ฟังก์ชันอื่น ๆ ของ "บริสุทธิ์" หรือ "ไม่บริสุทธิ์" นี่อาจเป็นจุดเข้าใช้งานของคุณจาก RESTful API
ตัวเลือก Class 2 : บริการทางธุรกิจบริสุทธิ์ เหล่านี้เป็นคลาสที่คงที่ซึ่งมีฟังก์ชั่น "เพียว" ใน FP "บริสุทธิ์" หมายถึงไม่มีผลข้างเคียง มันไม่ได้ตั้งค่ารัฐหรือการมีอยู่อย่างชัดเจนทุกที่ (ดูหมายเหตุ 5)
ดังนั้นเมื่อคุณนึกถึงคลาสในภาษาเชิงวัตถุที่ถูกใช้ในสถาปัตยกรรมเชิงบริการมันไม่เพียง แต่เป็นประโยชน์ต่อ OO Code ของคุณเท่านั้นมันเริ่มทำให้ฟังก์ชั่นการเขียนโปรแกรมฟังก์ชั่นเข้าใจง่าย
หมายเหตุ
หมายเหตุ 1 : การออกแบบเชิงวัตถุ "Rich" หรือ "Active-Record" ดั้งเดิมยังคงอยู่ มีรหัสดั้งเดิมมากมายเช่นนั้นเมื่อผู้คน "ทำถูกต้อง" เมื่อสิบปีที่แล้ว ครั้งสุดท้ายที่ฉันเห็นโค้ดประเภทนั้น (ทำอย่างถูกต้อง) มาจากวิดีโอเกม Codebase ใน C ++ ที่ซึ่งพวกเขาควบคุมหน่วยความจำอย่างแม่นยำและมีพื้นที่ จำกัด มาก อย่าบอกว่า FP และ Service-Oriented Architecture เป็นสัตว์ร้ายและไม่ควรพิจารณาถึงฮาร์ดแวร์ แต่พวกเขามีความสามารถในการเปลี่ยนแปลงอย่างต่อเนื่องได้รับการดูแลรักษามีขนาดข้อมูลที่เปลี่ยนแปลงและด้านอื่น ๆ เป็นลำดับความสำคัญ ในวิดีโอเกมและเครื่อง AI คุณสามารถควบคุมสัญญาณและข้อมูลได้อย่างแม่นยำมาก
หมายเหตุ 2 : รูปแบบโดเมนไม่มีพฤติกรรมแบบ Polymorphic และไม่มีการพึ่งพาภายนอก พวกเขาคือ "โดดเดี่ยว" ไม่ได้หมายความว่าพวกเขาจะต้องเป็นโรคโลหิตจาง 100% พวกเขาสามารถมีเหตุผลมากมายที่เกี่ยวข้องกับการก่อสร้างและการเปลี่ยนแปลงคุณสมบัติที่ไม่แน่นอนถ้าใช้เช่นนั้น ดู DDD "วัตถุค่า" และหน่วยงานโดย Eric Evans และ Mark Seemann
หมายเหตุ 3 : Linq และ Lambda นั้นเป็นเรื่องธรรมดามาก แต่เมื่อผู้ใช้สร้างฟังก์ชั่นใหม่พวกเขาไม่ค่อยใช้ Func หรือ Callable เป็นพารามิเตอร์ในขณะที่ใน FP มันจะแปลกที่จะเห็นแอพที่ไม่มีฟังก์ชั่นตามรูปแบบนั้น
หมายเหตุ 4 : ไม่สับสนกับความหลากหลายกับการสืบทอด CatModel อาจสืบทอด AnimalBase เพื่อกำหนดคุณสมบัติที่สัตว์มักจะมี แต่ที่ผมแสดงรุ่นเช่นนี้เป็นกลิ่นรหัส หากคุณเห็นรูปแบบนี้คุณอาจพิจารณาแยกย่อยและเปลี่ยนเป็นข้อมูล
หมายเหตุ 5 : ฟังก์ชั่นที่บริสุทธิ์สามารถ (และทำ) ยอมรับฟังก์ชั่นเป็นพารามิเตอร์ ฟังก์ชั่นที่เข้ามาอาจไม่บริสุทธิ์ แต่อาจบริสุทธิ์ สำหรับวัตถุประสงค์ในการทดสอบมันจะบริสุทธิ์เสมอ แต่ในการผลิตแม้ว่าจะได้รับการปฏิบัติเหมือนบริสุทธิ์ แต่ก็อาจมีผลข้างเคียง แต่นั่นไม่ได้เปลี่ยนความจริงที่ว่าฟังก์ชั่นบริสุทธิ์นั้นบริสุทธิ์ แม้ว่าฟังก์ชั่นพารามิเตอร์อาจไม่บริสุทธิ์ ไม่สับสน! : D