คำนำ
ในบทนี้เราจะอธิบายบทที่สี่ของการดำเนินการตามหลักการสำคัญห้าประการของจาวาสคริปต์ที่เป็นของแข็งหลักการแยกอินเตอร์เฟส
ข้อความภาษาอังกฤษต้นฉบับ: http://freshbrewedcode.com/derekgreeer/2012/01/08/solid-javascript-the-interface-segregation-principle/
หมายเหตุ: ผู้เขียนบทความนี้ค่อนข้างน่าประทับใจดังนั้นลุงก็รู้สึกหดหู่ที่จะเข้าใจ เพียงแค่อ่านตามที่คุณต้องการอย่าติดอยู่ในนั้น
คำอธิบายของหลักการแยกส่วนต่อประสานคือ:
การคัดลอกรหัสมีดังนี้:
ลูกค้าไม่ควรถูกบังคับให้ต้องพึ่งพาวิธีการที่พวกเขาไม่ได้ใช้
ลูกค้าไม่ควรถูกบังคับให้พึ่งพาวิธีการที่พวกเขาไม่ได้ใช้
เมื่อเมธอดอินเตอร์เฟสที่ผู้ใช้ขึ้นอยู่กับผู้ใช้รายอื่นใช้เท่านั้นและไม่ได้ใช้มันจะต้องใช้อินเทอร์เฟซเหล่านี้ กล่าวอีกนัยหนึ่งหากผู้ใช้อาศัยอินเทอร์เฟซที่ไม่ได้ใช้ แต่ใช้โดยผู้ใช้รายอื่นเมื่อผู้ใช้รายอื่นแก้ไขอินเทอร์เฟซผู้ใช้ทั้งหมดที่อาศัยอยู่ในอินเทอร์เฟซจะได้รับผลกระทบ เห็นได้ชัดว่านี่เป็นการละเมิดหลักการของการเปิดและปิดและไม่ใช่สิ่งที่เราคาดหวัง
ISP หลักการแยกส่วนต่อประสานนั้นค่อนข้างคล้ายกับความรับผิดชอบเดี่ยว ทั้งสองใช้เพื่อรวมความรับผิดชอบในการทำงาน ในความเป็นจริง ISP สามารถเข้าใจได้เพื่อแปลงโปรแกรมด้วยความรับผิดชอบเดียวกับวัตถุที่มีส่วนต่อประสานสาธารณะ
อินเตอร์เฟส JavaScript
เราจะปฏิบัติตามหลักการนี้ภายใต้ JavaScript ได้อย่างไร? ท้ายที่สุด JavaScript ไม่มีคุณสมบัติของอินเทอร์เฟซ หากอินเทอร์เฟซเป็นสิ่งที่เราต้องการสร้างสัญญาและแยกแยะผ่านประเภทนามธรรมที่จัดทำโดยภาษาบางอย่างอาจกล่าวได้ว่ามันโอเค แต่ JavaScript มีอินเทอร์เฟซรูปแบบอื่น ในรูปแบบการออกแบบหนังสือองค์ประกอบองค์ประกอบของซอฟต์แวร์เชิงวัตถุที่นำกลับมาใช้ใหม่ได้เราพบคำจำกัดความของอินเทอร์เฟซ:
http://www.amazon.com/design-patterns-elements-reusable-object-oriented/dp/0201633612
การดำเนินการใด ๆ ที่ประกาศโดยวัตถุมีชื่อการดำเนินการวัตถุพารามิเตอร์และค่าส่งคืนของการดำเนินการ เราเรียกมันว่าลายเซ็นของผู้ประกอบการ
การดำเนินการทั้งหมดที่ประกาศในวัตถุเรียกว่าอินเทอร์เฟซของวัตถุนี้ อินเทอร์เฟซของวัตถุแสดงข้อมูลคำขอทั้งหมดที่เกิดขึ้นในวัตถุนี้
ไม่ว่าภาษาจะให้โครงสร้างแยกต่างหากเพื่อเป็นตัวแทนของอินเทอร์เฟซวัตถุทั้งหมดมีส่วนต่อประสานโดยนัยที่ประกอบด้วยคุณสมบัติและวิธีการทั้งหมดของวัตถุ อ้างถึงรหัสต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
var exampleBinder = {};
extrambinder.modelobserver = (function () {
/* ตัวแปรส่วนตัว*/
กลับ {
สังเกต: ฟังก์ชั่น (โมเดล) {
/* รหัส*/
กลับ Newmodel;
-
onchange: ฟังก์ชั่น (โทรกลับ) {
/* รหัส*/
-
-
-
extrambinder.viewadaptor = (function () {
/* ตัวแปรส่วนตัว*/
กลับ {
ผูก: ฟังก์ชั่น (โมเดล) {
/* รหัส*/
-
-
-
extrambinder.bind = function (โมเดล) {
/* ตัวแปรส่วนตัว*/
extrambinder.modelobserver.onchange (/ * โทรกลับการโทรกลับ */);
var om = examplebinder.modelobserver.observe (รุ่น);
extrambinder.viewadaptor.bind (OM);
กลับ OM;
-
ไลบรารีคลาสตัวอย่างด้านบนใช้การเชื่อมโยงสองทาง อินเทอร์เฟซสาธารณะที่เปิดเผยโดยไลบรารีคลาสนี้เป็นวิธีการผูกซึ่งฟังก์ชั่นของการแจ้งเตือนการเปลี่ยนแปลงและการโต้ตอบมุมมองที่ใช้ในการผูกจะถูกนำมาใช้โดยวัตถุแยกต่างหาก modelobserver และ viewadaptor ตามลำดับ วัตถุเหล่านี้มีความหมายว่าการใช้งานเฉพาะของวิธีการผูกอินเตอร์เฟสสาธารณะ
แม้ว่า JavaScript จะไม่ได้จัดเตรียมประเภทอินเทอร์เฟซเพื่อสนับสนุนสัญญาของวัตถุ แต่อินเทอร์เฟซโดยนัยของวัตถุยังคงสามารถให้กับผู้ใช้โปรแกรมเป็นสัญญาได้
ISP และ JavaScript
ส่วนย่อยบางส่วนที่เราพูดถึงด้านล่างนี้เป็นผลกระทบของการละเมิดหลักการแยกส่วนต่อประสานใน JavaScript ดังที่ได้เห็นข้างต้นแม้ว่ามันจะน่าเสียดายที่จะใช้หลักการของการแยกอินเทอร์เฟซในโปรแกรม JavaScript แต่ก็ไม่ได้ทรงพลังเท่ากับภาษาที่พิมพ์แบบคงที่ ลักษณะภาษาของ JavaScript บางครั้งทำให้อินเทอร์เฟซที่เรียกว่าไม่ติดเล็กน้อย
การตระหนักถึงความชั่วช้า
ในภาษาที่พิมพ์แบบคงที่หนึ่งในเหตุผลของการละเมิดหลักการของ ISP คือการดำเนินการที่เสื่อมโทรม ต้องใช้วิธีการที่กำหนดไว้ในอินเทอร์เฟซทั้งหมดใน Java และ C# หากคุณต้องการเพียงไม่กี่วิธีจะต้องใช้วิธีอื่น ๆ (สามารถนำไปใช้โดยข้อยกเว้นที่ว่างเปล่าหรือการขว้างปา) ใน JavaScript หากจำเป็นต้องใช้อินเทอร์เฟซบางส่วนในวัตถุเท่านั้นมันก็ไม่สามารถแก้ปัญหาการใช้งานที่เสื่อมสภาพได้แม้ว่าจะไม่จำเป็นต้องบังคับให้มีการใช้งานอินเตอร์เฟสด้านบน อย่างไรก็ตามการดำเนินการนี้ยังคงละเมิดหลักการของการเปลี่ยนริกเตอร์
การคัดลอกรหัสมีดังนี้:
var rectangle = {
พื้นที่: ฟังก์ชั่น () {
/* รหัส*/
-
วาด: ฟังก์ชั่น () {
/* รหัส*/
-
-
var geometryApplication = {
getLargestRectangle: ฟังก์ชั่น (สี่เหลี่ยม) {
/* รหัส*/
-
-
var drawingapplication = {
DrawRectangles: ฟังก์ชั่น (สี่เหลี่ยม) {
/* รหัส*/
-
-
เมื่อทางเลือกสี่เหลี่ยมผืนผ้าเพื่อตอบสนองความต้องการ getlargestrectangle ของการเชื่อมต่อรูปทรงเรขาคณิตของวัตถุใหม่มันต้องการเฉพาะวิธีพื้นที่สี่เหลี่ยมผืนผ้า () แต่มันละเมิด LSP (เพราะไม่สามารถใช้วิธีการวาดที่สามารถใช้ในวิธีการ Drawrectangles)
การมีเพศสัมพันธ์แบบคงที่
อีกเหตุผลหนึ่งสำหรับการละเมิด ISP ในภาษาที่พิมพ์แบบคงที่คือการมีเพศสัมพันธ์แบบคงที่ ในภาษาที่พิมพ์แบบคงที่อินเทอร์เฟซมีบทบาทสำคัญในโปรแกรมการออกแบบคู่กันอย่างหลวม ๆ ไม่ว่าจะเป็นภาษาแบบไดนามิกหรือแบบคงที่บางครั้งวัตถุอาจจำเป็นต้องสื่อสารระหว่างผู้ใช้ลูกค้าหลายราย (เช่นสถานะที่ใช้ร่วมกัน) สำหรับภาษาที่พิมพ์แบบคงที่ทางออกที่ดีที่สุดคือการใช้อินเทอร์เฟซบทบาทซึ่งช่วยให้ผู้ใช้สามารถโต้ตอบกับวัตถุ (ซึ่งอาจจำเป็นต้องอยู่ในหลายบทบาท) เนื่องจากการใช้งานเพื่อแยกแยะพฤติกรรมของผู้ใช้และพฤติกรรมที่ไม่เกี่ยวข้อง ไม่มีปัญหาดังกล่าวใน JavaScript เนื่องจากวัตถุถูกแยกออกจากข้อได้เปรียบที่เป็นเอกลักษณ์ของภาษาไดนามิก
การมีเพศสัมพันธ์แบบความหมาย
สาเหตุหนึ่งที่พบบ่อยสำหรับการละเมิด ISP คือทั้งภาษาแบบไดนามิกและแบบคงที่ซึ่งเป็นการเชื่อมต่อแบบความหมาย การมีเพศสัมพันธ์ทางความหมายที่เรียกว่าเป็นการพึ่งพาซึ่งกันและกันนั่นคือพฤติกรรมของวัตถุขึ้นอยู่กับวัตถุอื่นซึ่งหมายความว่าหากผู้ใช้เปลี่ยนพฤติกรรมอย่างใดอย่างหนึ่งก็มีแนวโน้มที่จะส่งผลกระทบต่อผู้ใช้รายอื่น สิ่งนี้ยังเป็นการละเมิดหลักการของความรับผิดชอบเดี่ยว ปัญหานี้สามารถแก้ไขได้ผ่านการสืบทอดและการทดแทนวัตถุ
ความยืดหยุ่น
อีกเหตุผลหนึ่งสำหรับปัญหาคือเกี่ยวกับความสามารถในการปรับขนาด หลายคนจะให้ตัวอย่างเกี่ยวกับการโทรกลับเพื่อแสดงให้เห็นถึงความยืดหยุ่น (เช่นการตั้งค่าการโทรกลับหลังจากความสำเร็จใน AJAX) หากอินเทอร์เฟซดังกล่าวต้องการการใช้งานและมีวิธีการที่คุ้นเคยหรือหลายวิธีในการใช้งานของการใช้งานนี้ ISP จะกลายเป็นสิ่งสำคัญมาก กล่าวคือเมื่ออินเทอร์เฟซอินเทอร์เฟซจำเป็นต้องใช้วิธีการหลายวิธีการใช้งานจะซับซ้อนมากและอาจทำให้อินเทอร์เฟซเหล่านี้มีความรับผิดชอบที่ไม่ยึดติด นี่คืออินเทอร์เฟซไขมันที่เรามักพูดถึง
สรุป
ลักษณะภาษาแบบไดนามิกใน JavaScript ทำให้การใช้งานอินเตอร์เฟสที่ไม่ติดน้อยของเรามีอิทธิพลน้อยกว่าภาษาที่พิมพ์แบบคงที่ แต่หลักการของการแยกอินเทอร์เฟซยังคงมีฟังก์ชั่นในรูปแบบการเขียนโปรแกรม JavaScript