เพียงเพราะระบบมีความซับซ้อนไม่ได้หมายความว่าคุณจะต้องทำให้มันซับซ้อน หากคุณมีคลาสที่มีการพึ่งพา (หรือผู้ทำงานร่วมกัน) มากเกินไปเช่นนี้:
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
ขจัดความต้องการในการจัดการทั้งการพึ่งพาและปล่อยให้หนึ่งในนั้นจัดการการโทรเหล่านั้นแทน ในการจัดกลุ่มนี้ก็เป็นที่ชัดเจนว่าจะมีการอ้างอิงถึงD1
D2
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 (หรืออย่างน้อยมักจะ)" เป็นทางเลือกของการใช้การก่อสร้างหรือวิธีการแบบคงที่จะทำให้วัตถุที่ย่อยง่ายต่อการสร้างคุณสามารถใช้หนึ่งรูปแบบการสร้างของเหลว