เพียงเพราะระบบมีความซับซ้อนไม่ได้หมายความว่าคุณจะต้องทำให้มันซับซ้อน หากคุณมีคลาสที่มีการพึ่งพา (หรือผู้ทำงานร่วมกัน) มากเกินไปเช่นนี้:
public class MyAwesomeClass {
public class MyAwesomeClass(IDependency1 _d1, IDependency2 _d2, ... , IDependency20 _d20) {
// Assign it all
}
}
... ถ้าเช่นนั้นมันซับซ้อนเกินไปและคุณไม่ได้ติดตามSRPจริง ๆใช่ไหม? ฉันพนันได้เลยว่าถ้าคุณจดบันทึกสิ่งที่MyAwesomeClassเกิดขึ้นบนบัตร CRCมันจะไม่เหมาะกับบัตรดัชนีหรือคุณต้องเขียนด้วยตัวอักษรที่อ่านไม่ออกจริงๆ
สิ่งที่คุณมีอยู่ที่นี่คือพวกคุณปฏิบัติตามหลักการแยกส่วนต่อประสานแทนเท่านั้นและอาจนำไปสู่สุดขั้ว แต่นั่นเป็นเรื่องราวอื่นทั้งหมด คุณสามารถยืนยันว่าการขึ้นต่อกันนั้นเป็นวัตถุโดเมน (ซึ่งเกิดขึ้น) อย่างไรก็ตามการมีคลาสที่จัดการกับวัตถุโดเมน 20 รายการในเวลาเดียวกันก็ยืดออกไปไกลเกินไป
TDD จะให้ตัวบ่งชี้ที่ดีเกี่ยวกับจำนวนชั้นเรียน โผงผาง; หากวิธีการทดสอบมีรหัสการตั้งค่าที่ใช้ตลอดไปในการเขียน (แม้ว่าคุณจะทำการทดสอบซ้ำ) คุณMyAwesomeClassอาจมีสิ่งที่ต้องทำมากเกินไป
ดังนั้นคุณจะแก้ปริศนานี้อย่างไร คุณย้ายความรับผิดชอบไปยังคลาสอื่น มีขั้นตอนบางอย่างที่คุณสามารถทำได้ในคลาสที่มีปัญหานี้:
- ระบุการกระทำทั้งหมด (หรือความรับผิดชอบ) ที่ชั้นเรียนของคุณทำด้วยการพึ่งพา
- จัดกลุ่มการกระทำตามการพึ่งพาที่เกี่ยวข้องอย่างใกล้ชิด
- Redelegate! I refactor แต่ละการกระทำที่ระบุให้แก่คลาสใหม่หรือ (สำคัญกว่า)
ตัวอย่างที่เป็นนามธรรมเกี่ยวกับความรับผิดชอบในการปรับโครงสร้าง
ให้Cเป็นระดับที่มีหลายอ้างอิงD1, D2, D3, D4ที่คุณต้อง refactor ใช้น้อย เมื่อเราระบุว่าวิธีใดที่Cเรียกใช้การพึ่งพาเราสามารถทำรายการง่าย ๆ
D1- performA(D2),performB()
D2 - performD(D1)
D3 - performE()
D4 - performF(D3)
เมื่อดูรายการเราจะเห็นว่าD1และD2มีความสัมพันธ์ซึ่งกันและกันเนื่องจากชั้นเรียนต้องการให้พวกเขาอยู่ด้วยกัน นอกจากนี้เรายังจะเห็นว่าความต้องการD4 D3ดังนั้นเราจึงมีสองกลุ่ม:
Group 1- D1<->D2
Group 2- D4->D3
การจัดกลุ่มเป็นตัวบ่งชี้ว่าชั้นเรียนมีความรับผิดชอบสองประการ
Group 1- หนึ่งสำหรับการจัดการการโทรสองวัตถุที่ต้องการซึ่งกันและกัน บางทีคุณอาจให้ชั้นเรียนของคุณCขจัดความต้องการในการจัดการทั้งการพึ่งพาและปล่อยให้หนึ่งในนั้นจัดการการโทรเหล่านั้นแทน ในการจัดกลุ่มนี้ก็เป็นที่ชัดเจนว่าจะมีการอ้างอิงถึงD1D2
Group 2- ความรับผิดชอบอื่น ๆ ต้องการวัตถุหนึ่งเพื่อเรียกอีกอย่างหนึ่ง D4จัดการไม่ได้D3แทนชั้นเรียนของคุณ? จากนั้นเราอาจจะสามารถกำจัดออกD3จากชั้นเรียนCโดยให้D4ทำการโทรแทน
อย่าเอาคำตอบของฉันไปตั้งไว้เป็นตัวอย่างเพราะนามธรรมและตั้งสมมติฐานมากมาย ฉันค่อนข้างมั่นใจว่ามีวิธีเพิ่มเติมในการรีแฟคเตอร์นี้ แต่อย่างน้อยขั้นตอนอาจช่วยให้คุณได้รับกระบวนการบางอย่างเพื่อย้ายความรับผิดชอบไปรอบ ๆ แทนที่จะแยกชั้นเรียนขึ้น
แก้ไข:
ท่ามกลางความคิดเห็น@Emmad Karemพูดว่า:
"ถ้าคลาสของคุณมี 20 พารามิเตอร์ในตัวสร้างมันไม่ได้ดูเหมือนว่าทีมของคุณจะรู้ว่า SRP คืออะไรถ้าคุณมีคลาสที่ทำเพียงสิ่งเดียวมันจะมีการพึ่งพา 20 ครั้งได้อย่างไร" - ฉันคิดว่าถ้าคุณ มีคลาสลูกค้ามันไม่แปลกที่มีพารามิเตอร์ 20 ตัวในตัวสร้าง
มันเป็นความจริงที่วัตถุ DAO มักจะมีพารามิเตอร์จำนวนมากซึ่งคุณต้องตั้งค่าในตัวสร้างของคุณและพารามิเตอร์มักจะเป็นประเภทที่เรียบง่ายเช่นสตริง อย่างไรก็ตามในตัวอย่างของCustomerคลาสคุณยังสามารถจัดกลุ่มคุณสมบัติของมันไว้ในคลาสอื่นเพื่อทำให้สิ่งต่าง ๆ ง่ายขึ้น เช่นการมีAddressคลาสที่มีถนนและZipcodeคลาสที่มีรหัสไปรษณีย์และจะจัดการกับตรรกะทางธุรกิจเช่นการตรวจสอบข้อมูลเช่นกัน:
public class Address {
private String street1;
//...
private Zipcode zipcode;
// easy to extend
public bool isValid() {
return zipcode.isValid();
}
}
public class Zipcode {
private string zipcode;
public bool isValid() {
// return regex match that zipcode contains numbers
}
}
สิ่งนี้จะกล่าวถึงต่อไปในบล็อกโพสต์"ไม่เคยไม่เคยไม่เคยใช้ String ใน Java (หรืออย่างน้อยมักจะ)" เป็นทางเลือกของการใช้การก่อสร้างหรือวิธีการแบบคงที่จะทำให้วัตถุที่ย่อยง่ายต่อการสร้างคุณสามารถใช้หนึ่งรูปแบบการสร้างของเหลว