ลองย้อนกลับไปดูภาพใหญ่ที่นี่
อะไรคือIDatabase
ความรับผิดชอบ 's?
มันมีการดำเนินการที่แตกต่างกันไม่กี่:
- แยกสตริงการเชื่อมต่อ
- เปิดการเชื่อมต่อกับฐานข้อมูล (ระบบภายนอก)
- ส่งข้อความไปยังฐานข้อมูล ข้อความสั่งฐานข้อมูลเพื่อแก้ไขสถานะ
- รับคำตอบจากฐานข้อมูลและแปลงเป็นรูปแบบที่ผู้โทรสามารถใช้ได้
- ปิดการเชื่อมต่อ
เมื่อดูรายการนี้คุณอาจกำลังคิดว่า "นี่ไม่ได้ละเมิด SRP หรือไม่" แต่ฉันไม่คิดว่ามันจะทำ ทั้งหมดของการดำเนินงานเป็นส่วนหนึ่งของเดี่ยวแนวคิดเหนียว: การจัดการการเชื่อมต่อ stateful ฐานข้อมูล (ระบบภายนอก) มันสร้างการเชื่อมต่อมันติดตามสถานะปัจจุบันของการเชื่อมต่อ (โดยเฉพาะอย่างยิ่งในการดำเนินการกับการเชื่อมต่ออื่น ๆ ) มันส่งสัญญาณเมื่อมีการกระทำสถานะปัจจุบันของการเชื่อมต่อ ฯลฯ ในแง่นี้มันทำหน้าที่เป็น API ที่ซ่อนรายละเอียดการใช้งานจำนวนมากที่ผู้โทรส่วนใหญ่ไม่สนใจ ตัวอย่างเช่นใช้ HTTP, ซ็อกเก็ต, ไพพ์, TCP แบบกำหนดเอง, HTTPS หรือไม่ รหัสการโทรไม่สนใจ มันแค่ต้องการส่งข้อความและรับการตอบกลับ นี่เป็นตัวอย่างที่ดีของการห่อหุ้ม
เราแน่ใจเหรอ เราแบ่งการดำเนินการเหล่านี้ออกจากกันไม่ได้ใช่ไหม อาจจะแต่ไม่มีประโยชน์ หากคุณพยายามที่จะแยกพวกเขาคุณจะยังคงต้องมีวัตถุกลางที่ช่วยให้การเชื่อมต่อเปิดและ / หรือจัดการสิ่งที่สถานะปัจจุบันคือ การดำเนินการอื่น ๆ ทั้งหมดนั้นเชื่อมโยงกับสถานะเดียวกันอย่างแน่นหนาและหากคุณพยายามที่จะแยกพวกมันพวกมันก็จะจบลงด้วยการมอบหมายให้กลับไปที่วัตถุเชื่อมต่อ การดำเนินการเหล่านี้เป็นไปตามธรรมชาติและเป็นเหตุเป็นผลควบคู่ไปกับรัฐและไม่มีทางที่จะแยกมันออกจากกันได้ การแยกตัวดีมากเมื่อเราทำได้ แต่ในกรณีนี้เราทำไม่ได้. อย่างน้อยก็ไม่มีโปรโตคอลไร้สัญชาติที่แตกต่างกันมากที่จะพูดคุยกับฐานข้อมูลและนั่นจะทำให้เกิดปัญหาที่สำคัญมากเช่นการปฏิบัติตามข้อกำหนดเรื่องกรด นอกจากนี้ในกระบวนการพยายามแยกการดำเนินการเหล่านี้ออกจากการเชื่อมต่อคุณจะถูกบังคับให้เปิดเผยรายละเอียดเกี่ยวกับโปรโตคอลที่ผู้โทรไม่สนใจเนื่องจากคุณต้องการวิธีส่งข้อความ "โดยพลการ" ไปยังฐานข้อมูล
โปรดทราบว่าความจริงที่เรากำลังเผชิญกับโปรโตคอล stateful สวยออกกฎทางเลือกสุดท้ายของคุณ (ผ่านสตริงการเชื่อมต่อเป็นพารามิเตอร์)
เราต้องการตั้งค่าสตริงการเชื่อมต่อหรือไม่?
ใช่. คุณไม่สามารถเปิดการเชื่อมต่อจนกว่าคุณจะมีสตริงการเชื่อมต่อและคุณไม่สามารถทำอะไรกับโปรโตคอลจนกว่าคุณจะเปิดการเชื่อมต่อ ดังนั้นจึงไม่มีประโยชน์ที่จะมีวัตถุเชื่อมต่อโดยไม่มีวัตถุ
เราจะแก้ปัญหาในการกำหนดสตริงการเชื่อมต่อได้อย่างไร?
ปัญหาที่เราพยายามแก้ไขคือเราต้องการให้วัตถุอยู่ในสถานะใช้งานได้ตลอดเวลา นิติบุคคลประเภทใดที่ใช้ในการจัดการสถานะในภาษา OO วัตถุไม่ใช่อินเตอร์เฟส การเชื่อมต่อไม่มีสถานะที่จะจัดการ เนื่องจากปัญหาที่คุณพยายามแก้ไขเป็นปัญหาการจัดการสถานะอินเทอร์เฟซไม่เหมาะสมจริงๆที่นี่ คลาสนามธรรมเป็นธรรมชาติมากขึ้น ดังนั้นให้ใช้คลาสนามธรรมกับคอนสตรัคเตอร์
คุณอาจต้องการพิจารณาเปิดการเชื่อมต่อจริงระหว่างตัวสร้างเช่นกันเนื่องจากการเชื่อมต่อนั้นไร้ประโยชน์ก่อนที่จะเปิด ที่จะต้องมีprotected Open
วิธีนามธรรมตั้งแต่กระบวนการเปิดการเชื่อมต่ออาจมีเฉพาะฐานข้อมูล มันจะเป็นความคิดที่ดีที่จะทำให้ConnectionString
คุณสมบัติอ่านได้เฉพาะในกรณีนี้เนื่องจากการเปลี่ยนสตริงการเชื่อมต่อหลังจากเปิดการเชื่อมต่อจะไม่มีความหมาย (สุจริตฉันจะทำให้อ่านได้เท่านั้นถ้าคุณต้องการการเชื่อมต่อกับสายอื่นทำวัตถุอื่น)
เราต้องการอินเทอร์เฟซเลยหรือไม่?
อินเทอร์เฟซที่ระบุข้อความพร้อมใช้งานที่คุณสามารถส่งผ่านการเชื่อมต่อและชนิดของการตอบสนองที่คุณสามารถรับกลับอาจมีประโยชน์ สิ่งนี้จะทำให้เราสามารถเขียนโค้ดที่เรียกใช้การดำเนินการเหล่านี้ แต่ไม่ได้เชื่อมโยงกับตรรกะของการเปิดการเชื่อมต่อ แต่นั่นคือประเด็น: การจัดการการเชื่อมต่อไม่ได้เป็นส่วนหนึ่งของอินเทอร์เฟซของ "ฉันสามารถส่งข้อความอะไรได้บ้างและข้อความใดที่ฉันสามารถกลับไป / จากฐานข้อมูลได้" ดังนั้นสตริงการเชื่อมต่อไม่ควรเป็นส่วนหนึ่งของสิ่งนั้น อินเตอร์เฟซ.
หากเราไปเส้นทางนี้รหัสของเราอาจมีลักษณะเช่นนี้:
interface IDatabase {
void ExecuteNoQuery(string sql);
void ExecuteNoQuery(string[] sql);
//Various other methods all requiring ConnectionString to be set
}
abstract class ConnectionStringDatabase : IDatabase {
public string ConnectionString { get; }
public Database(string connectionString) {
this.ConnectionString = connectionString;
this.Open();
}
protected abstract void Open();
public abstract void ExecuteNoQuery(string sql);
public abstract void ExecuteNoQuery(string[] sql);
//Various other methods all requiring ConnectionString to be set
}