ไฮเบอร์เนตคืออะไร? พื้นฐานของการนำ Hibernate Core ไปใช้
เผยแพร่แล้ว: 2013-04-17ไฮเบอร์เนตเป็นโปรเจ็กต์เฟรมเวิร์กการคงอยู่ของ Java แบบโอเพ่นซอร์ส ทำการแมปเชิงสัมพันธ์ของอ็อบเจ็กต์ที่มีประสิทธิภาพและฐานข้อมูลการสืบค้นโดยใช้ HQL และ SQL
โดยทั่วไปแล้ว ไลบรารีที่ใช้กันอย่างแพร่หลายนั้นได้รับการออกแบบและใช้งานเป็นอย่างดี และเป็นเรื่องที่น่าสนใจมากที่จะเรียนรู้จากแนวทางปฏิบัติที่ดีที่สุดในการเขียนโค้ดจากพวกเขา
มาดูภายในไลบรารีแกนไฮเบอร์เนตและค้นพบคีย์การออกแบบบางส่วน
ในโพสต์นี้ Hibernate Core ได้รับการวิเคราะห์โดย JArchitect
เพื่อเจาะลึกถึงการออกแบบและการใช้งาน
แพ็คเกจตามคุณสมบัติ
Package-by-feature
ใช้แพ็คเกจเพื่อแสดงชุดคุณสมบัติ โดยจะวางรายการทั้งหมดที่เกี่ยวข้องกับคุณลักษณะเดียว (และเฉพาะคุณลักษณะนั้น) ลงในไดเร็กทอรี/แพ็คเกจเดียว ส่งผลให้บรรจุภัณฑ์มีความต่อเนื่องกันสูงและมีความเป็นโมดูลสูง และมีการมีเพศสัมพันธ์ระหว่างบรรจุภัณฑ์น้อยที่สุด สิ่งของที่ทำงานร่วมกันอย่างใกล้ชิดจะวางชิดกัน
คอร์ไฮเบอร์เนตมีแพ็คเกจมากมาย แต่ละแพ็คเกจเกี่ยวข้องกับฟีเจอร์เฉพาะ hql, sql และอื่นๆ
ข้อต่อ
ควรใช้คัปปลิ้งต่ำเนื่องจากการเปลี่ยนแปลงในพื้นที่หนึ่งของแอปพลิเคชันจะต้องมีการเปลี่ยนแปลงน้อยลงตลอดทั้งแอปพลิเคชันทั้งหมด ในระยะยาว สิ่งนี้สามารถบรรเทาเวลา ความพยายาม และค่าใช้จ่ายที่เกี่ยวข้องกับการปรับเปลี่ยนและเพิ่มคุณสมบัติใหม่ให้กับแอปพลิเคชันได้อย่างมาก
ประโยชน์หลักสามประการที่ได้จากการใช้อินเทอร์เฟซ:
- อินเทอร์เฟซให้วิธีการกำหนดสัญญาที่ส่งเสริมการใช้ซ้ำ หากวัตถุใช้อินเทอร์เฟซ วัตถุนั้นจะต้องเป็นไปตามมาตรฐาน วัตถุที่ใช้วัตถุอื่นเรียกว่าผู้บริโภค ส่วนต่อประสานคือสัญญาระหว่างวัตถุกับผู้บริโภค
- อินเทอร์เฟซยังให้ระดับนามธรรมที่ทำให้โปรแกรมเข้าใจได้ง่ายขึ้น อินเทอร์เฟซช่วยให้นักพัฒนาเริ่มพูดคุยเกี่ยวกับวิธีทั่วไปที่โค้ดทำงานโดยไม่ต้องเจาะลึกรายละเอียดมากนัก
- อินเทอร์เฟซบังคับใช้การมีเพศสัมพันธ์ระหว่างส่วนประกอบต่ำ ทำให้ง่ายต่อการปกป้องผู้ใช้อินเทอร์เฟซจากการเปลี่ยนแปลงการใช้งานในคลาสที่ใช้อินเทอร์เฟซ
มาค้นหาอินเทอร์เฟซทั้งหมดที่กำหนดโดย Hibernate Core เพื่อที่เราใช้ CQLinq
เพื่อสืบค้นฐานรหัส
1 |
from t in Types where t . IsInterface select t |
หากเป้าหมายหลักของเราคือบังคับให้มีการเชื่อมต่อต่ำ มีข้อผิดพลาดทั่วไปเมื่อใช้อินเทอร์เฟซที่อาจทำลายยูทิลิตี้ของการใช้อินเทอร์เฟซเหล่านี้ เป็นการใช้คลาสที่เป็นรูปธรรมแทนอินเทอร์เฟซ และเพื่ออธิบายปัญหานี้ให้ดีขึ้น ลองมาดูตัวอย่างต่อไปนี้:
คลาส A ใช้ Interface IA ที่มีเมธอดคำนวณ () คลาสผู้บริโภค C ถูกใช้งานเช่นนั้น
1 2 3 4 5 6 7 8 9 10 11 |
public class C < br > { … . public void calculate ( ) { … . . m_a . calculate ( ) ; … . } A m_a ; } |
Class C แทนที่จะอ้างอิงถึงอินเทอร์เฟซ IA จะอ้างอิงถึงคลาส A ในกรณีนี้ เราสูญเสียผลประโยชน์จากการมีเพศสัมพันธ์ที่ต่ำ และการใช้งานนี้มีข้อเสียหลักสองประการ:
- หากเราตัดสินใจใช้ IA แบบอื่น เราต้องเปลี่ยนรหัสของคลาส C
- หากมีการเพิ่มวิธีการบางอย่างใน A ที่ไม่มีอยู่ใน IA และ C ใช้วิธีการเหล่านั้น เราจะสูญเสียผลประโยชน์ตามสัญญาของการใช้อินเทอร์เฟซด้วย
C# แนะนำความสามารถในการใช้งานอินเทอร์เฟซที่ชัดเจนสำหรับภาษาเพื่อให้แน่ใจว่าเมธอดจาก IA จะไม่ถูกเรียกจากการอ้างอิงถึงคลาสที่เป็นรูปธรรม แต่จะมาจากการอ้างอิงถึงอินเทอร์เฟซเท่านั้น เทคนิคนี้มีประโยชน์มากในการปกป้องนักพัฒนาจากการสูญเสียประโยชน์ของการใช้อินเทอร์เฟซ
ด้วย JArchitect เราสามารถตรวจสอบข้อผิดพลาดประเภทนี้ได้โดยใช้ CQLinq
แนวคิดคือการค้นหาวิธีการทั้งหมดจากคลาสคอนกรีตที่ใช้โดยตรงโดยวิธีอื่น
1 2 3 4 5 6 7 8 9 |
from m in Methods where m . NbMethodsCallingMe > 0 && m . ParentType . IsClass && ! m . ParentType . IsThirdParty && ! m . ParentType . IsAbstract let interfaces = m . ParentType . InterfacesImplemented from i in interfaces where i . Methods . Where ( a = > a . Name == m . Name && a . ParentType ! = m . ParentType ) . Count ( ) > 0 select new { m , m . ParentType , i } |
ตัวอย่างเช่น เมธอด getEntityPersister จาก SessionFactoryImpl ซึ่งใช้อินเทอร์เฟซ SessionFactoryImplementor เกี่ยวข้องกับปัญหานี้
มาค้นหาวิธีการเรียกโดยตรง SessionFactoryImpl.getEntityPersister
1 2 3 |
from m in Methods where m . IsUsing ( "org.hibernate.internal.SessionFactoryImpl.getEntityPersister(String)" ) select new { m , m . NbBCInstructions } |

เมธอดเช่น SessionImpl.instantiate เรียกใช้ getEntityPersister โดยตรง แทนที่จะส่งผ่านอินเทอร์เฟซ สิ่งที่ทำให้ประโยชน์ของการใช้อินเทอร์เฟซเสียไป โชคดีที่คอร์ไฮเบอร์เนตไม่มีวิธีการมากมายที่มีปัญหานี้
ต่อกับโถภายนอก
เมื่อใช้ libs ภายนอก จะเป็นการดีกว่าที่จะตรวจสอบว่าเราสามารถเปลี่ยน lib บุคคลที่สามได้อย่างง่ายดายโดยไม่ส่งผลกระทบต่อแอปพลิเคชันทั้งหมดหรือไม่ มีหลายสาเหตุที่สนับสนุนให้เราเปลี่ยน lib บุคคลที่สาม
lib อื่นสามารถ:
- มีคุณสมบัติเพิ่มเติม
- มีพลังมากขึ้น
- ปลอดภัยยิ่งขึ้น
มาดูตัวอย่างของ antlr lib
ซึ่งเคยแยกวิเคราะห์การสืบค้น hql และลองนึกดูว่า parser อื่นที่ทรงพลังกว่า antlr ถูกสร้างขึ้น เราสามารถเปลี่ยน antlr ด้วย parser ใหม่ได้อย่างง่ายดายหรือไม่
ในการตอบคำถามนี้ ให้ค้นหาวิธีการจากโหมดไฮเบอร์เนตที่ใช้โดยตรง:
1 2 3 |
from m in Methods where m . IsUsing ( "antlr-2.7.7" ) select new { m , m . NbBCInstructions } |
และอันไหนที่ใช้ทางอ้อม:
1 2 3 4 |
from m in Projects . WithNameNotIn ( "antlr-2.7.7" ) . ChildMethods ( ) let depth0 = m . DepthOfIsUsing ( "antlr-2.7.7" ) where depth0 > 1 orderby depth0 select new { m , depth0 } |
หลายวิธีใช้ antlr โดยตรงซึ่งทำให้แกนไฮเบอร์เนตทำงานร่วมกับมันได้โดยตรง และการเปลี่ยน antlr ด้วยอันอื่นไม่ใช่เรื่องง่าย ข้อเท็จจริงนี้ไม่ได้หมายความว่าเรามีปัญหาในการออกแบบไฮเบอร์เนต แต่เราต้องระวังเมื่อใช้ lib บุคคลที่สามและตรวจสอบว่า lib บุคคลที่สามต้องต่ำควบคู่ไปกับแอปพลิเคชันหรือไม่
การติดต่อกัน
หลักความรับผิดชอบเดียวระบุว่าชั้นเรียนควรมีหนึ่งเหตุผลในการเปลี่ยนแปลง ชั้นเรียนดังกล่าวมีความเหนียวแน่น โดยทั่วไป ค่า LCOM
ที่สูงจะระบุคลาสที่เหนียวแน่นได้ไม่ดี มีเมตริก LCOM หลายตัว LCOM ใช้ค่าในช่วง [0-1] LCOMHS (HS ย่อมาจาก Henderson-Sellers) ใช้ค่าในช่วง [0-2] โปรดทราบว่าเมตริก LCOMHS มักจะถือว่ามีประสิทธิภาพมากกว่าในการตรวจจับประเภทที่ไม่เกาะติดกัน
ค่า LCOMHS ที่สูงกว่า 1 ถือว่าน่าตกใจ
โดยทั่วไปชั้นเรียนที่เกี่ยวข้องกันมากขึ้นคือชั้นเรียนที่มีวิธีการและสาขามากมาย
ลองค้นหาประเภทที่มีวิธีการและฟิลด์มากมาย
1 2 3 4 |
from t in Types where ( t . Methods . Count ( ) > 40 | | t . Fields . Count ( ) > 40 ) && t . IsClass orderby t . Methods . Count ( ) descending select new { t , t . InstanceMethods , t . Fields , t . LCOMHS } |
แบบสอบถามนี้มีเพียงไม่กี่ประเภทที่เกี่ยวข้อง และสำหรับทั้งหมดนั้น LCOMHS มีค่าน้อยกว่า 1
การใช้คำอธิบายประกอบ
การพัฒนาโดยใช้คำอธิบายประกอบช่วยให้นักพัฒนา Java พ้นจากความเจ็บปวดจากการกำหนดค่าที่ยุ่งยาก และให้คุณสมบัติอันทรงพลังแก่เราในการปลดปล่อยซอร์สโค้ดจากโค้ดสำเร็จรูป โค้ดผลลัพธ์ยังมีโอกาสน้อยที่จะมีข้อบกพร่อง
มาค้นหาคำอธิบายประกอบทั้งหมดที่กำหนดโดยแกนไฮเบอร์เนตกัน
1 |
from t in Types where t . IsAnnotationClass && ! t . IsThirdParty select t |
มีการกำหนดคำอธิบายประกอบจำนวนมาก สิ่งที่ทำให้นักพัฒนาใช้โหมดไฮเบอร์เนตได้ง่าย และไม่ต้องปวดหัวกับไฟล์การกำหนดค่า
บทสรุป
Hibernate Core เป็นตัวอย่างที่ดีของโครงการโอเพ่นซอร์สที่ควรเรียนรู้ อย่าลังเลที่จะดูภายใน