สิ่งที่คุณต้องรู้เกี่ยวกับ Solid Principles ใน Java

ในบทความนี้คุณจะได้เรียนรู้โดยละเอียดเกี่ยวกับหลักการ Solid ใน java พร้อมตัวอย่างและความสำคัญพร้อมตัวอย่างชีวิตจริง

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



ประวัติของหลักการ SOLID ใน Java

โรเบิร์ตซี. มาร์ตินให้หลักการออกแบบเชิงวัตถุ 5 ประการและใช้ตัวย่อ“ S.O.L.I.D” เมื่อคุณใช้หลักการทั้งหมดของ S.O.L.I.D ในลักษณะรวมกันคุณจะพัฒนาซอฟต์แวร์ที่สามารถจัดการได้ง่ายขึ้น คุณสมบัติอื่น ๆ ของการใช้ S.O.L.I.D คือ:

  • หลีกเลี่ยงกลิ่นรหัส
  • รหัสหักเหอย่างรวดเร็ว
  • สามารถทำการพัฒนาซอฟต์แวร์ที่ปรับเปลี่ยนได้หรือคล่องตัว

เมื่อคุณใช้หลักการของ S.O.L.I.D ในการเขียนโค้ดคุณจะเริ่มเขียนโค้ดที่มีทั้งประสิทธิภาพและประสิทธิผล



ความหมายของ S.O.L.I.D คืออะไร?

Solid แสดงถึงหลักการห้าประการของ java ซึ่ง ได้แก่ :

  • : หลักการรับผิดชอบเดียว
  • หรือ : หลักการเปิด - ปิด
  • : หลักการเปลี่ยนตัว Liskov
  • ผม : หลักการแยกส่วนต่อประสาน
  • : หลักการผกผันการพึ่งพา

ในบล็อกนี้เราจะพูดถึงหลักการ SOLID ทั้งห้าของ Java โดยละเอียด



หลักการความรับผิดชอบเดียวใน Java

มันพูดว่าอะไร?

โรเบิร์ตซี. มาร์ตินอธิบายว่าชั้นเรียนหนึ่งควรมีความรับผิดชอบเพียงหนึ่งเดียว

ตามหลักความรับผิดชอบเดียวควรมีเพียงเหตุผลเดียวที่ต้องเปลี่ยนคลาส หมายความว่าชั้นเรียนควรมีภารกิจหนึ่งที่ต้องทำ หลักการนี้มักเรียกว่าเป็นอัตวิสัย

หลักการสามารถเข้าใจได้ดีด้วยตัวอย่าง ลองนึกภาพว่ามีชั้นเรียนที่ดำเนินการต่อไปนี้

  • เชื่อมต่อกับฐานข้อมูล

  • อ่านข้อมูลบางส่วนจากตารางฐานข้อมูล

  • สุดท้ายเขียนลงในไฟล์

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

ตัวอย่างเช่นคลาส Automobile สามารถเริ่มหรือหยุดตัวเองได้ แต่งานล้างเป็นของคลาส CarWash ในอีกตัวอย่างหนึ่งคลาสหนังสือมีคุณสมบัติในการจัดเก็บชื่อและข้อความของตัวเอง แต่งานพิมพ์หนังสือต้องเป็นของคลาส Book Printer คลาสเครื่องพิมพ์หนังสืออาจพิมพ์ไปยังคอนโซลหรือสื่ออื่น แต่การอ้างอิงดังกล่าวจะถูกลบออกจากคลาสหนังสือ

เหตุใดจึงจำเป็นต้องมีหลักการนี้

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

ตัวอย่างเพื่อชี้แจงหลักการนี้:

สมมติว่าคุณถูกขอให้ใช้บริการ UserSetting ซึ่งผู้ใช้สามารถเปลี่ยนการตั้งค่าได้ แต่ก่อนหน้านั้นผู้ใช้จะต้องได้รับการพิสูจน์ตัวตน วิธีหนึ่งในการนำไปใช้คือ:

UserSettingService คลาสสาธารณะ {โมฆะสาธารณะ changeEmail (ผู้ใช้ผู้ใช้) {if (checkAccess (user)) {// Grant option to change}} public boolean checkAccess (User user) {// ตรวจสอบว่าผู้ใช้ถูกต้องหรือไม่ }}

ทุกอย่างดูดีจนกว่าคุณจะต้องการใช้รหัส checkAccess ซ้ำในที่อื่นหรือคุณต้องการเปลี่ยนแปลงวิธีที่กำลังดำเนินการ checkAccess ในทั้ง 2 กรณีคุณจะต้องเปลี่ยนคลาสเดียวกันและในกรณีแรกคุณจะต้องใช้ UserSettingService เพื่อตรวจสอบการเข้าถึงด้วย
วิธีหนึ่งในการแก้ไขปัญหานี้คือการแตก UserSettingService เป็น UserSettingService และ SecurityService และย้ายรหัส checkAccess ไปที่ SecurityService

UserSettingService คลาสสาธารณะ {โมฆะสาธารณะ changeEmail (ผู้ใช้ผู้ใช้) {if (SecurityService.checkAccess (ผู้ใช้)) {// ให้ตัวเลือกในการเปลี่ยนแปลง}}} SecurityService คลาสสาธารณะ {public static boolean checkAccess (User user) {// ตรวจสอบการเข้าถึง }}

เปิดหลักการปิดใน Java

Robert C. Martin อธิบายว่าส่วนประกอบของซอฟต์แวร์ควรเปิดให้มีการขยาย แต่ปิดเพื่อแก้ไข

เพื่อให้ถูกต้องตามหลักการนี้ชั้นเรียนควรเขียนในลักษณะที่ทำงานได้อย่างไม่มีที่ติโดยไม่มีข้อสันนิษฐานว่าผู้คนในอนาคตจะเข้ามาและเปลี่ยนแปลงได้ ดังนั้นคลาสควรยังคงปิดอยู่สำหรับการแก้ไข แต่ควรมีตัวเลือกในการขยาย วิธีการขยายชั้นเรียน ได้แก่ :

  • รับช่วงต่อจากคลาส

  • เขียนทับพฤติกรรมที่ต้องการจากชั้นเรียน

  • ขยายพฤติกรรมบางอย่างของชั้นเรียน

ตัวอย่างที่ยอดเยี่ยมของหลักการเปิดปิดสามารถเข้าใจได้ด้วยความช่วยเหลือของเบราว์เซอร์ คุณจำการติดตั้งส่วนขยายในเบราว์เซอร์ Chrome ได้ไหม

ฟังก์ชันพื้นฐานของเบราว์เซอร์ Chrome คือการท่องเว็บไซต์ต่างๆ คุณต้องการตรวจสอบไวยากรณ์เมื่อคุณเขียนอีเมลโดยใช้เบราว์เซอร์ Chrome หรือไม่ถ้าใช่คุณสามารถใช้ส่วนขยาย Grammarly ซึ่งจะให้คุณตรวจสอบไวยากรณ์ในเนื้อหา

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

เหตุใดจึงต้องใช้หลักการนี้?

OCP มีความสำคัญเนื่องจากชั้นเรียนอาจมาหาเราผ่านไลบรารีของบุคคลที่สาม เราควรจะสามารถขยายคลาสเหล่านั้นได้โดยไม่ต้องกังวลว่าคลาสพื้นฐานเหล่านั้นสามารถรองรับส่วนขยายของเราได้หรือไม่ แต่การสืบทอดอาจนำไปสู่คลาสย่อยซึ่งขึ้นอยู่กับการใช้คลาสฐาน เพื่อหลีกเลี่ยงปัญหานี้แนะนำให้ใช้อินเทอร์เฟซ สิ่งที่เป็นนามธรรมเพิ่มเติมนี้นำไปสู่การมีเพศสัมพันธ์ที่หลวม

สมมติว่าเราต้องคำนวณพื้นที่ของรูปทรงต่างๆ เราเริ่มต้นด้วยการสร้างคลาสสำหรับ Rectangle รูปร่างแรกของเราซึ่งมีความยาว 2 แอตทริบิวต์& ความกว้าง

สี่เหลี่ยมผืนผ้าระดับสาธารณะ {public double length public double width}

ต่อไปเราจะสร้างคลาสเพื่อคำนวณพื้นที่ของสี่เหลี่ยมผืนผ้านี้ซึ่งมีวิธีการคำนวณRectangleAreaซึ่งใช้สี่เหลี่ยมผืนผ้าเป็นพารามิเตอร์อินพุตและคำนวณพื้นที่

คลาสสาธารณะ AreaCalculator {public double คำนวณRectangleArea (สี่เหลี่ยมผืนผ้าสี่เหลี่ยมผืนผ้า) {return rectangle.length * rectangle.width}}

จนถึงตอนนี้ดีมาก ทีนี้สมมติว่าเราได้วงกลมรูปร่างที่สอง ดังนั้นเราจึงสร้าง Circle คลาสใหม่ทันทีด้วยรัศมีแอตทริบิวต์เดียว

แวดวงสาธารณะ {รัศมีคู่สาธารณะ}

จากนั้นเราปรับเปลี่ยน Areacalculatorคลาสเพื่อเพิ่มการคำนวณวงกลมโดยใช้วิธีการใหม่ calculaArea ()

คลาสสาธารณะ AreaCalculator {public double คำนวณRectangleArea (สี่เหลี่ยมผืนผ้าสี่เหลี่ยมผืนผ้า) {return rectangle.length * rectangle.width} public double คำนวณCircleArea (วงกลมวงกลม) {return (22/7) * circle.radius * circle.radius}}

อย่างไรก็ตามโปรดทราบว่ามีข้อบกพร่องในวิธีที่เราออกแบบโซลูชันข้างต้น

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

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

การปรับเปลี่ยนการออกแบบข้างต้นเพื่อให้สอดคล้องกับหลักการเปิด / ปิด:

ตอนนี้ให้เราเห็นการออกแบบที่หรูหรากว่าซึ่งแก้ไขข้อบกพร่องในการออกแบบข้างต้นโดยยึดตามหลักการเปิด / ปิด ก่อนอื่นเราจะทำให้การออกแบบขยายได้ สำหรับสิ่งนี้เราต้องกำหนดประเภทพื้นฐาน Shape ก่อนและให้ Circle & Rectangle ใช้อินเตอร์เฟส Shape

อินเทอร์เฟซสาธารณะ Shape {public double คำนวณArea ()} คลาสสาธารณะ Rectangle ใช้รูปร่าง {double length double width public double adjustmentArea () {return length * width}} public class Circle implements Shape {public double radius public double CalculatorArea () {return (22 / 7) * รัศมี * รัศมี}}

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

คลาสสาธารณะ AreaCalculator {public double คำนวณShapeArea (รูปร่างรูปร่าง) {return shape.calculateArea ()}}

AreaCalculator นี้ขณะนี้คลาสได้ขจัดข้อบกพร่องในการออกแบบของเราที่ระบุไว้ข้างต้นอย่างสมบูรณ์และมอบโซลูชันที่สะอาดซึ่งเป็นไปตามหลักการเปิด - ปิด มาดูหลักการ SOLID อื่น ๆ ใน Java กัน

Liskov Substitution Principle ใน Java

Robert C. Martin อธิบายว่าประเภท Derived ต้องสามารถทดแทนได้อย่างสมบูรณ์สำหรับประเภทพื้นฐาน

หลักการแทนที่ Liskov ถือว่า q (x) เป็นคุณสมบัติพิสูจน์ได้เกี่ยวกับเอนทิตีของ x ซึ่งเป็นของประเภท T ตอนนี้ตามหลักการนี้ q (y) ควรสามารถพิสูจน์ได้สำหรับอ็อบเจ็กต์ y ที่อยู่ในประเภท S และ S เป็นประเภทย่อยของ T. ตอนนี้คุณสับสนและไม่รู้ว่าหลักการแทนที่ Liskov หมายถึงอะไร? คำจำกัดความของมันอาจจะซับซ้อนเล็กน้อย แต่จริงๆแล้วมันค่อนข้างง่าย สิ่งเดียวคือทุกคลาสย่อยหรือคลาสที่ได้รับควรถูกแทนที่สำหรับคลาสแม่หรือคลาสฐาน

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

เหตุใดจึงต้องใช้หลักการนี้?

วิธีนี้หลีกเลี่ยงการใช้มรดกในทางที่ผิด ช่วยให้เราปฏิบัติตามความสัมพันธ์แบบ“ is-a” นอกจากนี้เรายังสามารถกล่าวได้ว่าคลาสย่อยต้องปฏิบัติตามสัญญาที่กำหนดโดยคลาสพื้นฐาน ในแง่นี้มันเกี่ยวข้องกับออกแบบตามสัญญาที่อธิบายครั้งแรกโดย Bertrand Meyer ตัวอย่างเช่นการบอกว่าวงกลมเป็นวงรีประเภทหนึ่ง แต่วงกลมไม่มีจุดโฟกัสสองอันหรือแกนหลัก / รอง

LSP นิยมอธิบายโดยใช้ตัวอย่างสี่เหลี่ยมจัตุรัสและสี่เหลี่ยมผืนผ้า ถ้าเราถือว่าความสัมพันธ์ ISA ระหว่าง Square และ Rectangle ดังนั้นเราจึงเรียกว่า 'Square is a Rectangle' รหัสด้านล่างแสดงถึงความสัมพันธ์

คลาสสาธารณะ Rectangle {private int length private int public int getLength () {return length} public void setLength (int length) {this.length = length} public int getBreadth () {return breadth} public void setBreadth (int wide) { this.breadth = breadth} public int getArea () {return this.length * this.breadth}}

ด้านล่างนี้คือรหัสสำหรับ Square โปรดทราบว่า Square ขยายสี่เหลี่ยมผืนผ้า

คลาสสาธารณะ Square ขยาย Rectangle {โมฆะสาธารณะ setBreadth (ความกว้าง int) {super.setBreadth (ความกว้าง) super.setLength (ความกว้าง)} โมฆะสาธารณะ setLength (int length) {super.setLength (length) super.setBreadth (length)}}

ในกรณีนี้เราพยายามสร้างความสัมพันธ์ ISA ระหว่าง Square และ Rectangle โดยที่การเรียก 'Square is a Rectangle' ในโค้ดด้านล่างจะเริ่มทำงานโดยไม่คาดคิดหากมีการส่งอินสแตนซ์ของ Square ข้อผิดพลาดในการยืนยันจะเกิดขึ้นในกรณีของการตรวจสอบ 'พื้นที่' และการตรวจสอบ 'ความกว้าง' แม้ว่าโปรแกรมจะยุติลงเนื่องจากข้อผิดพลาดในการยืนยันเกิดขึ้นเนื่องจากความล้มเหลวของการตรวจสอบพื้นที่

LSPDemo คลาสสาธารณะ {โมฆะสาธารณะคำนวณArea (สี่เหลี่ยมผืนผ้า r) {r.setBreadth (2) r.setLength (3) ยืนยัน r.getArea () == 6: printError ('area', r) assert r.getLength () == 3: printError ('length', r) ยืนยัน r.getBreadth () == 2: printError ('breadth', r)} private String printError (String errorIdentifer, Rectangle r) {return 'Un expected value of' + errorIdentifer + ' เช่น '+ r.getClass (). getName ()} public static void main (String [] args) {LSPDemo lsp = new LSPDemo () // อินสแตนซ์ของ Rectangle ถูกส่งผ่าน lsp.calculateArea (Rectangle ใหม่ ()) // อินสแตนซ์ของ Square ถูกส่งผ่าน lsp.calculateArea (new Square ())}}

ชั้นเรียนแสดงให้เห็นถึงหลักการทดแทน Liskov (LSP) ตามหลักการแล้วฟังก์ชันที่ใช้การอ้างอิงไปยังคลาสพื้นฐานจะต้องสามารถใช้อ็อบเจ็กต์ของคลาสที่ได้รับมาโดยไม่รู้ตัว

ดังนั้นในตัวอย่างที่แสดงด้านล่างฟังก์ชันคำนวณพื้นที่ซึ่งใช้การอ้างอิงของ 'สี่เหลี่ยมผืนผ้า' ควรจะสามารถใช้อ็อบเจ็กต์ของคลาสที่ได้รับเช่น Square และตอบสนองความต้องการที่กำหนดโดยนิยามสี่เหลี่ยมผืนผ้า โปรดทราบว่าตามคำจำกัดความของ Rectangle สิ่งต่อไปนี้จะต้องเป็นจริงเสมอตามข้อมูลด้านล่าง:

  1. ความยาวจะต้องเท่ากับความยาวที่ส่งผ่านเมื่อป้อนข้อมูลไปยังเมธอดเสมอ setLength
  2. ความกว้างจะต้องเท่ากับความกว้างที่ส่งผ่านเป็นอินพุตไปยังเมธอดเสมอ setBreadth
  3. พื้นที่ต้องเท่ากับผลคูณของความยาวและความกว้างเสมอ

ในกรณีที่เราพยายามสร้างความสัมพันธ์ ISA ระหว่าง Square และ Rectangle เช่นที่เราเรียกว่า 'Square is a Rectangle' โค้ดด้านบนจะเริ่มทำงานโดยไม่คาดคิดหากอินสแตนซ์ของ Square ถูกส่งผ่านข้อผิดพลาด Assertion ในกรณีที่ตรวจสอบพื้นที่และตรวจสอบ สำหรับความกว้างแม้ว่าโปรแกรมจะยุติลงเนื่องจากข้อผิดพลาดในการยืนยันเกิดขึ้นเนื่องจากการตรวจสอบพื้นที่ล้มเหลว

คลาส Square ไม่ต้องการเมธอดเช่น setBreadth หรือ setLength คลาส LSPDemo จำเป็นต้องทราบรายละเอียดของคลาสที่ได้รับจาก Rectangle (เช่น Square) เพื่อเขียนโค้ดอย่างเหมาะสมเพื่อหลีกเลี่ยงข้อผิดพลาดในการขว้างปา การเปลี่ยนแปลงรหัสที่มีอยู่ทำลายหลักการเปิด - ปิดตั้งแต่แรก

หลักการแยกส่วนต่อประสาน

Robert C. Martin อธิบายว่าลูกค้าไม่ควรถูกบังคับให้ใช้วิธีการที่ไม่จำเป็นซึ่งพวกเขาจะไม่ใช้

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

ตัวอย่างเช่นอินเทอร์เฟซการบันทึกเดียวสำหรับการเขียนและการอ่านบันทึกมีประโยชน์สำหรับฐานข้อมูล แต่ไม่ใช่สำหรับคอนโซล การอ่านบันทึกไม่สมเหตุสมผลสำหรับเครื่องบันทึกคอนโซล ดำเนินการต่อด้วยหลักการ SOLID นี้ในบทความ Java

เหตุใดจึงต้องใช้หลักการนี้?

ขอบอกว่ามีอินเทอร์เฟซร้านอาหารซึ่งมีวิธีการรับคำสั่งซื้อจากลูกค้าออนไลน์ลูกค้าโทรเข้าหรือโทรศัพท์และลูกค้าวอล์กอิน นอกจากนี้ยังมีวิธีการจัดการการชำระเงินออนไลน์ (สำหรับลูกค้าออนไลน์) และการชำระเงินด้วยตนเอง (สำหรับลูกค้าวอล์กอินและลูกค้าทางโทรศัพท์เมื่อมีการส่งคำสั่งซื้อที่บ้าน)

การใช้รายการที่เชื่อมโยงในค

ตอนนี้ให้เราสร้าง Java Interface สำหรับ Restaurant และตั้งชื่อว่า RestaurantInterface.java

อินเทอร์เฟซสาธารณะ RestaurantInterface {โมฆะสาธารณะ acceptOnlineOrder () โมฆะสาธารณะ takeTelephoneOrder () โมฆะสาธารณะ payOnline () โมฆะสาธารณะ walkInCustomerOrder () โมฆะสาธารณะ payInPerson ()}

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

เริ่มต้นด้วยการใช้งาน RestaurantInterface สำหรับลูกค้าออนไลน์เป็น OnlineClientImpl.java

คลาสสาธารณะ OnlineClientImpl ใช้ RestaurantInterface {โมฆะสาธารณะ acceptOnlineOrder () {// ตรรกะสำหรับการสั่งซื้อออนไลน์} โมฆะสาธารณะ takeTelephoneOrder () {// ไม่สามารถใช้งานได้สำหรับการสั่งซื้อออนไลน์โยน UnsupportedOperationException ใหม่ ()} โมฆะสาธารณะ payOnline () {// ตรรกะสำหรับการจ่ายเงิน ออนไลน์} โมฆะสาธารณะ walkInCustomerOrder () {// ไม่สามารถใช้งานได้สำหรับการสั่งซื้อออนไลน์โยน UnsupportedOperationException ใหม่ ()} โมฆะสาธารณะ payInPerson () {// ใช้ไม่ได้สำหรับการสั่งซื้อทางออนไลน์โยนใหม่ UnsupportedOperationException ()}}
  • เนื่องจากโค้ดด้านบน (OnlineClientImpl.java) ใช้สำหรับการสั่งซื้อออนไลน์ให้โยน UnsupportedOperationException

  • ลูกค้าออนไลน์โทรศัพท์และวอล์กอินใช้การใช้งาน RestaurantInterface เฉพาะสำหรับลูกค้าแต่ละราย

  • คลาสการใช้งานสำหรับไคลเอนต์ Telephonic และไคลเอนต์ Walk-in จะมีวิธีการที่ไม่รองรับ

  • เนื่องจากวิธีการทั้ง 5 เป็นส่วนหนึ่งของ RestaurantInterface ชั้นเรียนการใช้งานจึงต้องใช้ทั้ง 5 วิธี

  • เมธอดที่คลาสการนำไปใช้งานแต่ละคลาสส่ง UnsupportedOperationException อย่างที่คุณเห็นได้อย่างชัดเจน - การนำวิธีการทั้งหมดไปใช้นั้นไม่มีประสิทธิภาพ

  • การเปลี่ยนแปลงใด ๆ ในวิธีการใด ๆ ของ RestaurantInterface จะถูกเผยแพร่ไปยังคลาสการใช้งานทั้งหมด จากนั้นการบำรุงรักษาโค้ดจะเริ่มยุ่งยากมากขึ้นและผลของการเปลี่ยนแปลงจะเพิ่มขึ้นเรื่อย ๆ

  • RestaurantInterface.java แบ่งหลักการความรับผิดชอบเดียวเนื่องจากตรรกะสำหรับการชำระเงินและสำหรับการจัดวางคำสั่งซื้อถูกรวมเข้าด้วยกันในอินเทอร์เฟซเดียว

เพื่อเอาชนะปัญหาดังกล่าวข้างต้นเราใช้หลักการแยกส่วนต่อประสานเพื่อปรับโครงสร้างการออกแบบข้างต้น

  1. แยกฟังก์ชันการชำระเงินและการจัดวางคำสั่งซื้อออกเป็นสองอินเทอร์เฟซแบบลีนที่แยกจากกันคือ PaymentInterface.java และ OrderInterface.java

  2. ลูกค้าแต่ละรายใช้ PaymentInterface และ OrderInterface ตัวอย่างเช่น - OnlineClient.java ใช้ OnlinePaymentImpl และ OnlineOrderImpl เป็นต้น

  3. ขณะนี้มีการแนบหลักการความรับผิดชอบเดียวเป็นอินเทอร์เฟซการชำระเงิน (PaymentInterface.java) และอินเทอร์เฟซการสั่งซื้อ (OrderInterface)

  4. การเปลี่ยนแปลงในคำสั่งซื้อหรืออินเทอร์เฟซการชำระเงินใด ๆ จะไม่มีผลกับอีกฝ่าย ตอนนี้พวกเขาเป็นอิสระไม่จำเป็นต้องดำเนินการดัมมี่ใด ๆ หรือโยน UnsupportedOperationException เนื่องจากแต่ละอินเทอร์เฟซมีวิธีการเท่านั้นที่จะใช้เสมอ

หลังจากสมัคร ISP

หลักการผกผันการพึ่งพา

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

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

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

เหตุใดจึงต้องใช้หลักการนี้?

ช่วยให้โปรแกรมเมอร์สามารถลบการอ้างอิงแบบฮาร์ดโค้ดเพื่อให้แอปพลิเคชันเชื่อมโยงกันอย่างหลวม ๆ และขยายได้

ชั้นเรียนสาธารณะ Student {private Address address public Student () {address = new Address ()}}

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

ด้วยเหตุนี้เราจึงสิ้นสุดหลักการ SOLID นี้ใน Java

ตรวจสอบไฟล์ โดย Edureka บริษัท การเรียนรู้ออนไลน์ที่เชื่อถือได้ซึ่งมีเครือข่ายผู้เรียนที่พึงพอใจมากกว่า 250,000 คนกระจายอยู่ทั่วโลก หลักสูตรการฝึกอบรมและการรับรอง Java J2EE และ SOA ของ Edureka ออกแบบมาสำหรับนักเรียนและผู้เชี่ยวชาญที่ต้องการเป็น Java Developer หลักสูตรนี้ออกแบบมาเพื่อให้คุณเริ่มต้นการเขียนโปรแกรม Java และฝึกอบรมแนวคิด Java ทั้งหลักและขั้นสูงพร้อมกับเฟรมเวิร์ก Java ต่างๆเช่น Hibernate & Spring

มีคำถามสำหรับเรา? โปรดระบุไว้ในส่วนความคิดเห็นของบล็อก 'หลักการแก้ปัญหาใน Java' และเราจะติดต่อกลับโดยเร็วที่สุด