มีภาษาการเขียนโปรแกรมที่ออกแบบมาเพื่อการฉีดแบบพึ่งพาหรือไม่?


21

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

มีภาษาใดบ้างที่ได้รับการออกแบบมาโดยเฉพาะเพื่อให้ง่ายต่อการใช้งานและในทางกลับกันทำให้การสร้างการพึ่งพาที่ซ่อนอยู่ยากหรือไม่?

ชี้แจง:

เนื่องจากข้อ จำกัด ของบางภาษา (ดูที่ Java ของคุณ) หลายคนมองว่าการช่วยเหลือเกี่ยวกับการเดินสายและการก่อสร้างเป็นส่วนหนึ่งของการฉีดขึ้นอยู่กับการพึ่งพา ที่นี่ฉันตั้งใจจะใช้ภาษาที่ออกแบบมาสำหรับ DI เพื่อแสดงว่าการพึ่งพานั้นไม่ได้ซ่อนอยู่ในผลข้างเคียง การมีการประชุมผ่านระบบการกำหนดค่าเช่นกันจะถูกเพิ่มน้ำเกรวี่

ฉันไม่ต้องการคำแนะนำภาษา มันเป็นคำถามทางประวัติศาสตร์ มีผู้เขียนภาษาคนใดตั้งไว้ให้ทำอย่างชัดเจนหรือไม่?


1
มีความเกี่ยวข้องอย่างยิ่งหากไม่ได้สำเนาซ้ำกันทั้งหมด: การฉีดการพึ่งพาสามารถรวมเข้ากับภาษาได้อย่างไร
Robert Harvey

Whee! 3K! ตอนนี้ฉันสามารถดูพวกเขาโหวตให้ปิดคำถามนี้ :) ขอบคุณสำหรับการโหวต
candied_orange

1
คุณควรอ่านโพสต์นั้น "มันมีอยู่จริง" เป็นคำถามที่น่าสนใจน้อยกว่ามากเว้นแต่คุณจะขยายออกไปเป็นบางอย่างเช่น "พวกเขาทำได้อย่างไร"
Robert Harvey

1
Haskell จะนับหรือไม่ ด้วยฟังก์ชั่นการเรียงลำดับขั้นสูงและการแก้ปัญหาคุณสามารถแก้ไขปัญหาส่วนใหญ่ที่ DI มักแก้ไขในภาษา OOP และด้วยความเข้มงวดในด้านความบริสุทธิ์คุณจึงถูกบังคับให้แยกด้านข้างเช่น IO ฯลฯ และฟังก์ชั่นไม่สามารถคิดสิ่งที่พวกเขา คุณไม่ได้รับการประชุมเกี่ยวกับการกำหนดค่าใด ๆ แต่ในทางกลับกันฉันก็ค่อยๆเคลื่อนตัวออกจากที่นั่นแม้ในรหัส OOP ของฉันทุกวันนี้เนื่องจากฉันสังเกตเห็นว่าทีมส่วนใหญ่ไม่สามารถเชื่อถือได้กับโครงการขนาดกลางและขนาดใหญ่
wasatz

1
@wasatz: ใช่ Haskell นับ "รูปแบบซอฟต์แวร์" ส่วนใหญ่เป็นเพียงการแก้ปัญหาข้อบกพร่องในภาษาการเขียนโปรแกรม
Robert Harvey

คำตอบ:


21

ใช่มีแน่นอน เรียงจาก

Newspeakไม่มีสถานะคงที่และไม่มีสถานะส่วนกลาง ซึ่งหมายความว่าวิธีเดียวที่เป็นไปได้ในการเข้าถึงการพึ่งพาคือการฉีดอย่างชัดเจน เห็นได้ชัดว่านี่หมายความว่าภาษาหรือในกรณีของ Newspeak ที่แม่นยำยิ่งขึ้น IDE ต้องทำให้การพึ่งพาง่ายขึ้นมิฉะนั้นภาษาจะไม่สามารถใช้งานได้

ดังนั้นภาษาไม่ได้ถูกออกแบบมาสำหรับ DI แต่ความจำเป็นสำหรับ DI นั้นเป็นผลมาจากการออกแบบภาษา

หากไม่มีสถานะคงที่และไม่มีสถานะโกลบอลคุณจะไม่สามารถ "เข้าถึง" อีเธอร์และดึงบางสิ่งออกมาได้ ตัวอย่างเช่นใน Java โครงสร้างแพ็กเกจคือสถานะคงที่ ฉันสามารถพูดได้java.lang.StringและฉันมีStringชั้นเรียนของตัวเอง ที่เป็นไปไม่ได้ใน Newspeak ทุกสิ่งที่คุณทำงานด้วยจะต้องได้รับการให้บริการอย่างชัดเจนกับคุณมิฉะนั้นคุณจะไม่สามารถทำได้ ดังนั้นทุกอย่างเป็นการพึ่งพาและทุกการพึ่งพานั้นชัดเจน

คุณต้องการสตริงหรือไม่ ก่อนอื่นคุณต้องถามstdlibวัตถุก่อนส่งมอบStringชั้น แหม แต่คุณจะเข้าถึงได้stdlibอย่างไร ก่อนอื่นคุณต้องขอplatformให้มือมอบstdlibสิ่งของให้คุณก่อน แหม แต่คุณจะเข้าถึงได้platformอย่างไร ก่อนอื่นคุณต้องขอให้คนอื่นมอบplatformสิ่งของให้คุณ โอ้ แต่คุณจะเข้าถึงคนนั้นได้อย่างไร? ก่อนอื่นคุณต้องขอให้คนอื่นมอบสิ่งของให้คุณก่อน

หลุมกระต่ายลงไปได้ไกลแค่ไหน? การเรียกซ้ำหยุดอยู่ที่ไหน ตลอดทางจริง มันไม่หยุด จากนั้นคุณจะเขียนโปรแกรมใน Newspeak ได้อย่างไร พูดอย่างเคร่งครัดคุณทำไม่ได้!

คุณต้องการเอนทิตี้ภายนอกที่เชื่อมโยงเข้าด้วยกัน ใน Newspeak เอนทิตีนั้นคือ IDE IDE เห็นโปรแกรมทั้งหมด มันสามารถโยงชิ้นส่วนต่างๆเข้าด้วยกันได้ รูปแบบมาตรฐานใน Newspeak คือคลาสกลางของแอ็พพลิเคชันของคุณมี accessor ที่เรียกว่าplatformและ Newspeak IDE จะแทรกออบเจกต์ลงใน accessor นั้นที่มีวิธีการที่จะคืนค่าความจำเป็นพื้นฐานของการเขียนโปรแกรม: StringคลาสNumberคลาสArrayคลาส และอื่น ๆ

หากคุณต้องการทดสอบแอปพลิเคชันของคุณคุณสามารถฉีดplatformออบเจกต์ซึ่งFileเมธอดส่งคืนคลาสด้วยวิธีจำลอง หากคุณต้องการปรับใช้แอปพลิเคชันของคุณไปยังคลาวด์คุณจะได้ฉีดแพลตฟอร์มที่FileAmazon S3 รองรับการใช้งานจริง ข้ามแพลตฟอร์ม GUIs ทำงานโดยการฉีดกรอบงาน GUI ที่แตกต่างกันสำหรับระบบปฏิบัติการที่แตกต่างกัน Newspeak ยังมีคอมไพเลอร์ Newspeak-to-ECMAScript และเฟรมเวิร์ก GUI ที่ได้รับการสนับสนุนจาก HTML ซึ่งช่วยให้คุณสามารถพอร์ตแอปพลิเคชั่น GUI ที่มีคุณสมบัติครบถ้วนจากเดสก์ท็อปดั้งเดิมไปยังเบราว์เซอร์โดยไม่มีการเปลี่ยนแปลง

หากคุณต้องการปรับใช้แอปพลิเคชันของคุณ IDE สามารถทำให้แอปพลิเคชันเป็นอนุกรมในวัตถุบนดิสก์ (ซึ่งแตกต่างจากบรรพบุรุษของมันคือ Smalltalk, Newspeak มีรูปแบบการจัดลำดับวัตถุนอกภาพ) คุณไม่จำเป็นต้องนำภาพทั้งหมดไปกับคุณอย่างแม่นยำเนื่องจากการอ้างอิงทั้งหมดจะถูกฉีดเข้าด้วยกัน: IDE รู้ว่าส่วนใดของระบบ ใช้และสิ่งที่มันไม่ได้ดังนั้นมันอนุกรมเป็นกราฟย่อยที่เชื่อมต่อของพื้นที่วัตถุที่ประกอบด้วยใบสมัครของคุณไม่มีอะไรเพิ่มเติม)

ทั้งหมดนี้ใช้งานได้ง่ายโดยการวางแนววัตถุให้สุดขั้ว: ทุกอย่างเป็นการเรียกใช้เมธอดเสมือน ("การส่งข้อความ" ในคำศัพท์ Smalltalk ซึ่ง Newspeak เป็นผู้สืบทอด) แม้แต่การค้นหาซูเปอร์คลาสก็เป็นการเรียกใช้เมธอดเสมือน! ใช้สิ่งที่ชอบ

class Foo extends Bar // using Java syntax for familiarity

หรือใน Newspeak:

class Foo = Bar () () : ()

ใน Java สิ่งนี้จะสร้างชื่อFooในเนมสเปซส่วนกลางแบบสแตติกและค้นหาBarในสเปซโกลบอลแบบคงที่และสร้างBar Fooซูเปอร์คลาส แม้แต่ใน Ruby ซึ่งเป็นไดนามิกมากกว่านี้จะยังคงสร้างค่าคงที่แบบคงที่ในเนมสเปซส่วนกลาง

ใน Newspeak เทียบเท่าประกาศวิธีการ: สร้างวิธีทะเยอทะยานที่มีชื่อFooและทำให้มันกลับมาระดับที่มีลักษณะขึ้น superclass Barของตนโดยเรียกวิธีการที่มีชื่อ หมายเหตุ: สิ่งนี้ไม่เหมือน Ruby ซึ่งคุณสามารถใส่โค้ดRuby ที่สามารถเรียกทำงานได้ใด ๆเป็นการประกาศ superclass แต่โค้ดจะถูกดำเนินการเพียงครั้งเดียวเมื่อสร้างคลาสและค่าส่งคืนของรหัสนั้นจะกลายเป็นซูเปอร์คลาสคงที่ ไม่ได้วิธีการBarนี้เรียกใช้สำหรับการค้นหาทุกวิธี!

สิ่งนี้มีความหมายที่ลึกซึ้งบางอย่าง:

  • เนื่องจาก mixin นั้นเป็นคลาสที่ยังไม่รู้จัก superclass ของมันและใน Newspeak superclass เป็นการเรียกเมธอดเสมือนแบบไดนามิกและไม่ทราบว่าทุกคลาสจะเป็น mixin โดยอัตโนมัติ คุณจะได้รับมิกซ์อินฟรี
  • เนื่องจากคลาสภายในเป็นเพียงการเรียกเมธอดที่ส่งคืนคลาสคุณสามารถแทนที่เมธอดนั้นในคลาสย่อยของคลาสภายนอกดังนั้นทุกคลาสจึงเสมือน คุณได้รับคลาสเสมือนฟรี:

    class Outer {
      class Inner { /* … */ }
    }
    
    class Sub extends Outer {
      override class Inner { /* … */ }
    }
    

    Newspeak:

    class Outer = () (
      class Inner = () () : ()
    ) : ()
    
    class Sub = Outer () (
      class Inner = () () : ()
    ) : ()
    
  • เนื่องจาก superclass เป็นเพียงการเรียกเมธอดที่ส่งคืนคลาสคุณสามารถแทนที่เมธอดนั้นในคลาสย่อยของคลาสภายนอกคลาสภายในที่กำหนดใน superclass สามารถมีซูเปอร์คลาสอื่นในคลาสย่อย คุณได้รับการสืบทอดลำดับชั้นของคลาสฟรี:

    class Outer {
      class MyCoolArray extends Array { /* … */ }
    }
    
    class Sub extends Outer {
      override class Array { /* … */ }
      // Now, for instances of `Sub`, `MyCoolArray` has a different superclass 
      // than for instances of `Outer`!!!
    }
    

    Newspeak:

    class Outer = () (
      class MyCoolArray = Array () () : ()
    ) : ()
    
    class Sub = Outer () (
      class Array = () () : ()
    ) : ()
    
  • และสุดท้ายสิ่งที่สำคัญที่สุดสำหรับการสนทนานี้: (เนื่องจากนอกเหนือจากสิ่งที่คุณกำหนดไว้ในชั้นเรียนของคุณอย่างชัดเจน) คุณสามารถโทรหาวิธีการในชั้นเรียนที่ล้อมรอบด้วยคำศัพท์เฉพาะของคุณและ superclass (es) ของคุณ ไม่สามารถเรียกใช้เมธอดใด ๆได้เลยยกเว้นวิธีที่จะทำการฉีดอย่างชัดแจ้ง: คลาสระดับบนสุดไม่มีคลาสที่ล้อมรอบซึ่งเมธอดที่สามารถเรียกใช้ได้และไม่สามารถมีซูเปอร์คลาสอื่นที่ไม่ใช่วิธีการเริ่มต้นเนื่องจากการประกาศซูเปอร์คลาสนั้น วิธีการโทรและมันก็เห็นได้ชัดว่าไม่สามารถไป superclass (มันเป็นsuperclass) และยังไม่สามารถไปยังคลาสที่ล้อมรอบด้วย lexically เนื่องจากไม่มี สิ่งนี้หมายความว่าคลาสระดับบนสุดถูกห่อหุ้มอย่างสมบูรณ์พวกเขาสามารถเข้าถึงสิ่งที่พวกเขาได้รับการฉีดอย่างชัดเจนและพวกเขาจะได้รับการฉีดสิ่งที่พวกเขาขออย่างชัดเจนเท่านั้น ในคำอื่น ๆ : ชั้นเรียนระดับบนสุดเป็นโมดูล คุณจะได้รับระบบโมดูลทั้งหมดฟรี ในความเป็นจริงแล้วจะมีความแม่นยำมากขึ้น: คลาสระดับบนสุดเป็นการประกาศโมดูลอินสแตนซ์ของมันคือโมดูล ดังนั้นคุณจะได้รับระบบโมดูลที่มีการประกาศพารามิเตอร์พาราเมตริกและโมดูลชั้นหนึ่งฟรีสิ่งที่หลาย ๆ แม้กระทั่งระบบโมดูลที่ซับซ้อนมากก็ไม่สามารถทำได้

เพื่อให้การฉีดที่ไม่เจ็บปวดทั้งหมดการประกาศคลาสมีโครงสร้างที่ผิดปกติ: ประกอบด้วยการประกาศสองรายการ หนึ่งคือตัวสร้างคลาสซึ่งไม่ใช่ตัวสร้างที่สร้างอินสแตนซ์ของคลาส แต่เป็นตัวสร้างที่สร้างสภาพแวดล้อมที่คลาสเนื้อความรัน ในไวยากรณ์เหมือน Java มันจะมีลักษณะดังนี้:

class Foo(platform) extends Bar {
  Array  = platform.collections.Array
  String = platform.lang.String
  File   = platform.io.File
| // separator between class constructor and class body
  class MyArray extends Array { /* … */ }
  // Array refers to the method defined above which in turn gets it from the 
  // platform object that was passed into the class "somehow"
}

Newspeak:

class Foo using: platform = Bar (
  Array = platform collections Array
  String = platform streams String 
  File = platform files ExternalReadWriteStream
) (
  class MyArray = Array () () : ()
) : ()

โปรดทราบว่าทางโปรแกรมเมอร์ Newspeak เป็นจริงจะไปดูชั้น (e) เป็นเช่นนี้Newspeak IDE แสดงคลาสที่ซ้อนกันหลายคลาส

แม้ว่าฉันไม่สามารถเริ่มทำมันได้อย่างยุติธรรม คุณจะต้องเล่นกับมันด้วยตัวเอง Gilad Bracha ได้พูดคุยเกี่ยวกับแง่มุมต่าง ๆ ของระบบรวมถึงความเป็นโมดุล เขาพูดยาวมาก (2 ชั่วโมง)ซึ่งเป็นชั่วโมงแรกที่มีการแนะนำภาษาอย่างละเอียดรวมถึงเรื่องราวแบบแยกส่วน บทที่ 2 ของแพลตฟอร์มการเขียนโปรแกรม Newspeakครอบคลุมโมดูลาร์ หากคุณอ่านNewspeak บน Squeak - คู่มือสำหรับ Perplexed (aka Newspeak-101)คุณจะรู้สึกถึงระบบ Newspeak by Exampleเป็นเอกสารสด (เช่นมันทำงานอยู่ภายในพอร์ต Newspeak-on-ECMASCript ทุกบรรทัดของโค้ดสามารถแก้ไขได้ทุกผลลัพธ์สามารถตรวจสอบได้) แสดงให้เห็นถึงไวยากรณ์พื้นฐาน

แต่จริงๆคุณต้องเล่นกับมัน มันแตกต่างจากภาษากระแสหลักทั้งหมดและแม้แต่ภาษาที่ไม่ใช่ภาษากระแสหลักส่วนใหญ่ที่ยากต่อการอธิบายมันต้องมีประสบการณ์


3
Meh ห้ามการใช้สถานะคงที่และสถานะส่วนกลางและคุณสามารถพูดได้เกี่ยวกับภาษาการเขียนโปรแกรมสมัยใหม่เกือบทุกภาษา
Robert Harvey

อยากรู้ว่าภาชนะฉีดที่ทำด้วยมือของฉันหลายคนเป็นโรงงานแบบคงที่ ไม่เคยคิดว่าเป็นสิ่งที่ไม่ดีมาก่อน
candied_orange

@ Jörgวิธีใดที่คุณสามารถสำรองคำตอบนี้ได้อีกเล็กน้อย? ฉัน googled "newspeaklanguage.org การพึ่งพาการฉีด" และขึ้นมาว่างเปล่า สิ่งที่ใกล้เคียงที่ฉันสามารถหาเป็นแบบนี้: news.ycombinator.com/item?id=9620561
candied_orange

@CandiedOrange: ฉันอยู่ในกระบวนการของการขยายคำตอบ แต่แล้ว "โลกแห่งความจริง" แทรกแซง มันดีกว่าไหม
Jörg W Mittag

3
@ JörgWMittagอึศักดิ์สิทธิ์! ก็แน่นอนว่า "มากกว่า" แขวนในขณะที่ฉันประเมิน "ดีกว่า" อาจต้องใช้พลังของการเยี่ยมชมห้องน้ำเพื่อผ่านสิ่งนี้
candied_orange

7

ภาษาการเขียนโปรแกรม Wakeออกแบบมาเพื่อใช้การฉีดอ้างอิง โดยทั่วไปจะมีกรอบการฉีดที่พึ่งพาอาศัยกันเป็นภาษาตัวเอง คลาสกำหนดพารามิเตอร์ที่พวกเขาneedและprovideคอมไพเลอร์ขอทุกอย่างขึ้น


6

มันไม่ใช่ภาษาที่มีประโยชน์จริง ๆ แต่ระบบที่อธิบายไว้ในบทความนี้มีผลที่น่าสนใจ: มันช่วยให้คุณสามารถเขียนคลาสนามธรรมโดยใช้คลาส / อินเทอร์เฟซแบบนามธรรม (รวมถึงการสร้างอินสแตนซ์) คลาสนามธรรมแต่ละคลาสที่คุณใช้ ณ จุดเริ่มต้น การทำเช่นนี้ทำให้ไม่จำเป็นต้องใช้การฉีดแบบพึ่งพาในกรณีอย่างน้อยที่สุดตัวอย่างเช่น (การใช้ Java เวอร์ชันขยายที่มีคุณลักษณะนี้) เราสามารถใช้โค้ดนี้ได้:

public interface I {
    void something ();
)

public class Concrete implements I {
    public void something () { ... }
}

public class Client {
    I myI;
    public Client (I injected) { myI = injected; }
    ...
}

...

    Client c = new Client (new Concrete());
    ...

และแทนที่ลูกค้าและการใช้งานด้วย:

public class Client {
   I myI = new I();
   ...
}

   Client c = new Client { I -> Concrete } ();

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


น่าสนใจ สิ่งนี้ทำให้ฉันนึกถึงสมาชิกประเภทของสกาล่าซึ่งสามารถถูกแทนที่ในคลาสย่อยและนามธรรมที่เหลือในซูเปอร์คลาส สมาชิกประเภทบทคัดย่อรวมกับคำอธิบายประกอบแบบ Self-Type เป็นพื้นฐานของวิธีการของสกาล่าในการสร้างแบบแยกส่วนและการพึ่งพา ฉันไม่แปลกใจเลยที่บทความนี้ได้รับการอ้างถึงโดยMartin Oderskyผู้ออกแบบของ Scala และGilad Brachaผู้ออกแบบ Newspeak
Jörg W Mittag

0

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

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