بالكاد أحتاج إلى مناقشة سبب إعادة استخدام الكود. إعادة استخدام الكود عادة ما يجعل تطوير البرنامج أسرع ويقلل من الأخطاء. بمجرد تغليف قطعة رمز وإعادة استخدامها ، من الضروري التحقق من جزء صغير جدًا من التعليمات البرمجية لضمان صحة البرنامج. إذا كنت بحاجة فقط إلى فتح اتصال قاعدة البيانات وإغلاقها في مكان واحد خلال التطبيق ، فمن الأسهل بكثير التأكد من أن الاتصال طبيعي. لكنني متأكد من أنك تعرف كل هذا بالفعل.
هناك نوعان من رموز إعادة الاستخدام ، التي أسميها أنواع إعادة الاستخدام:
النوع الأول هو إعادة استخدام وظيفية ، وهو النوع الأكثر شيوعًا لإعادة الاستخدام. هذا هو أيضا نوع من إتقان لمعظم المطورين. وهذا هو ، إعادة استخدام مجموعة من التعليمات اللاحقة لأداء بعض العمليات.
النوع الثاني هو إعادة استخدام السياق ، أي وظائف مختلفة أو رموز التشغيل يتم تغليفها بين نفس السياقات ، ويتم تغليف نفس السياق كرمز إعادة الاستخدام (يشير السياق هنا إلى سلسلة من تعليمات العملية نفسها). على الرغم من أنه أصبح أكثر شعبية في انعكاس التحكم ، إلا أنه ليس شائعًا. علاوة على ذلك ، لا يتم وصف إعادة استخدام السياق بشكل صريح ، لذلك لا يتم استخدامه من قبل النظام مثل إعادة الاستخدام الوظيفي. أتمنى أن تتغير بعد قراءة هذا المقال.
إعادة استخدام الوظيفة
إعادة الاستخدام الوظيفي هو النوع الأكثر شيوعًا لإعادة الاستخدام. إنها إعادة استخدام مجموعة من التعليمات التي تنفذ نوعًا من التشغيل. الطريقتان التاليتان هما قراءة البيانات من قاعدة البيانات:
القائمة العامة readallusers () {connection connection = null ؛ String SQL = "SELECT * من المستخدمين" ؛ قائمة المستخدمين = new ArrayList () ؛ حاول {connection = openConnection () ؛ بيان reparedstatement = connection.preparestatement (SQL) ؛ نتائج resultse = state.executequery () ؛ بينما (result.next ()) {// إعادة استخدام مستخدم رمز المستخدم = مستخدم جديد () ؛ user.setName (result.getString ("name")) ؛ user.setemail (result.getString ("email")) ؛ user.add (user) ؛ // end Reuse Code} result.close () ؛ بيان. close () ؛ إرجاع المستخدمين ؛ } catch (sqlexception e) {// تجاهل الآن} أخيرًا {// تجاهل الآن}} القائمة العامة للقائمة readuSofStatus (حالة السلسلة) {connection = null ؛ String SQL = "SELECT * من المستخدمين أين الحالة =؟" ؛ قائمة المستخدمين = new ArrayList () ؛ حاول {connection = openConnection () ؛ بيان reparedstatement = connection.preparestatement (SQL) ؛ بيان. setString (1 ، الحالة) ؛ نتائج resultse = state.executequery () ؛ بينما (result.next ()) {// إعادة استخدام مستخدم رمز المستخدم = مستخدم جديد () ؛ user.setName (result.getString ("name")) ؛ user.setemail (result.getString ("email")) ؛ user.add (user) ؛ // end Reuse Code} result.close () ؛ بيان. close () ؛ إرجاع المستخدمين ؛ } catch (sqlexception e) {// تجاهل الآن} أخيرًا {// تجاهل الآن}}بالنسبة للمطورين ذوي الخبرة ، قد يكون من الممكن اكتشاف الكود القابل لإعادة الاستخدام قريبًا. المكان الذي يتم فيه التعليق على "رمز إعادة الاستخدام" في الكود أعلاه هو نفسه ، لذلك يمكن تغليف إعادة الاستخدام. هذه هي العمليات التي تقرأ سجلات المستخدم في مثيلات المستخدم. يمكن تغليف خطوط التعليمات البرمجية هذه في أساليبها الخاصة ، على سبيل المثال:
. user.setName (result.getString ("name")) ؛ user.setemail (result.getString ("email")) ؛ user.add (user) ؛ إرجاع المستخدم ؛ }الآن ، اتصل بالطريقة القارئ () في الطريقتين أعلاه (يوضح المثال التالي الطريقة الأولى فقط):
القائمة العامة readallusers () {connection connection = null ؛ String SQL = "SELECT * من المستخدمين" ؛ قائمة المستخدمين = new ArrayList () ؛ حاول {connection = openConnection () ؛ بيان reparedstatement = connection.preparestatement (SQL) ؛ نتائج resultse = state.executequery () ؛ بينما (result.next ()) {users.add (readuser (result))} result.close () ؛ بيان. close () ؛ إرجاع المستخدمين ؛ } catch (sqlexception e) {// تجاهل الآن} أخيرًا {// تجاهل الآن}}يمكن أيضًا إخفاء طريقة ReadUser () في فئتها الخاصة باستخدام Modifier Private.
ما سبق حول إعادة استخدام الوظائف. إعادة الاستخدام الوظيفي هي تغليف مجموعة من الإرشادات التي تؤدي عمليات محددة من خلال الأساليب أو الفئات لتحقيق الغرض من إعادة الاستخدام.
العمليات المعلمة
في بعض الأحيان تريد إعادة استخدام مجموعة من العمليات ، ولكن هذه العمليات ليست هي نفسها في أي مكان تستخدمه بالضبط. على سبيل المثال ، يفتح كل من READALLUSERS () و readuSersofStatus () كلاهما اتصالًا ، وإعداد عبارة ، وتنفيذها ، وحلقة من خلال مجموعة النتائج. الفرق الوحيد هو أن القراءاتوفستاتوس () يتطلب تعيين معلمة على الجهة المعد. يمكننا تغليف جميع العمليات في طريقة ReadUserList (). كما هو موضح أدناه:
قائمة خاصة readUserList (String SQL ، String [] Parameters) {connection connection = null ؛ قائمة المستخدمين = new ArrayList () ؛ حاول {connection = openConnection () ؛ بيان reparedstatement = connection.preparestatement (SQL) ؛ لـ (int i = 0 ؛ i <parameters.length ؛ i ++) {state.setString (i ، parameters [i]) ؛ } resultset result = ittupe.executequery () ؛ بينما (result.next ()) {users.add (readuser (result))} result.close () ؛ بيان. close () ؛ إرجاع المستخدمين ؛ } catch (sqlexception e) {// تجاهل الآن} أخيرًا {// تجاهل الآن}} الآن نسمي طريقة readUserList(...) من readAllUsers() و readUsersOfStatus() وإعطاء معلمات تشغيل مختلفة:
القائمة العامة readallusers () {return readUserList ("حدد * من المستخدمين" ، سلسلة جديدة [] {}) ؛} القائمة العامة القائمة readUsersWithStatus (حالة السلسلة) {return readUserList ("SELECT * from user" ، new String [] {{الحالة}) ؛}}أعتقد أنه يمكنك العثور على طرق أفضل أخرى لتنفيذ وظائف إعادة الاستخدام ومعلمةها لتسهيل استخدامها.
إعادة استخدام السياق
يختلف إعادة استخدام السياق قليلاً عن إعادة استخدام الميزة. إعادة استخدام السياق هي إعادة استخدام سلسلة من التعليمات ، ويتم دائمًا تنفيذ العمليات المختلفة بين هذه التعليمات. بمعنى آخر ، إعادة استخدام البيانات قبل وبعد سلوكيات مختلفة. لذلك فإن إعادة استخدام السياق يؤدي في كثير من الأحيان إلى انعكاس فئات نمط التحكم. يعد إعادة استخدام السياق وسيلة فعالة للغاية لإعادة استخدام الاستثناءات ، وإدارة دورة حياة الاتصال والمعاملات ، وتكرار التدفق والإغلاق ، والعديد من السياقات التشغيلية الشائعة الأخرى.
فيما يلي طريقتان تتم مع InputStream:
Public void printstream (inputStream inputStream) يلقي ioException {if (inputStream == null) return ؛ IoException استثناء = فارغ ؛ حاول {int character = inputStream.Read () ؛ بينما (الحرف! = -1) {system.out.print ((char) حرف) ؛ // أحرف مختلفة = inputStream.Read () ؛ }} أخيرًا {try {inputStream.close () ؛ } catch (ioException e) {if (issessive == null) throw e ؛ }}} السلسلة العامة readStream (inputStream inputStream) يلقي ioException {StringBuffer Buffer = new StringBuffer () ؛ // مختلف إذا (inputStream == NULL) ؛ IoException استثناء = فارغ ؛ حاول {int character = inputStream.Read () ؛ بينما (الحرف! = -1) {buffer.append ((char) حرف) ؛ // أحرف مختلفة = inputStream.Read () ؛ } return buffer.toString () ؛ // مختلفة} أخيرًا {try {inputStream.close () ؛ } catch (ioException e) {if (issessive == null) throw e ؛ }}}الطريقتان مختلفتان عن عملية التدفق. لكن السياق حول هذه العمليات هو نفسه. يكرر رمز السياق ويغلق inputStream. بالإضافة إلى الاختلافات في استخدام علامات التعليق ، فإن الرمز أعلاه هو رمز السياق الخاص به.
كما هو موضح أعلاه ، يتضمن السياق التعامل مع الاستثناء ويضمن إغلاق الدفق بشكل صحيح بعد التكرار. إن كتابة هذا الخطأ في معالجة الأخطاء ورمز إصدار الموارد مرارًا وتكرارًا أمر مرهق ومعرض للخطأ. تعتبر معالجة الأخطاء ومعالجة الاتصال الصحيح أكثر تعقيدًا في معاملات JDBC. من الواضح أنه من الأسهل كتابة التعليمات البرمجية مرة واحدة وإعادة استخدامه في أي مكان.
لحسن الحظ ، فإن طريقة تغليف السياق بسيطة. إنشاء فئة سياق ووضع السياق العام فيه. في استخدام السياق ، يتم استخلاص تعليمات التشغيل المختلفة في واجهة التشغيل ، ثم يتم تغليف كل عملية في الفئة التي تنفذ واجهة التشغيل (تسمى فئة العملية هنا). تحتاج فقط إلى إدراج مثيل فئة العملية في السياق. يمكن القيام بذلك عن طريق تمرير مثيل لفئة العملية كمعلمة إلى مُنشئ كائن السياق ، أو عن طريق تمرير مثيل لفئة العملية كمعلمة إلى طريقة التنفيذ المحددة للسياق.
يوضح ما يلي كيفية فصل المثال أعلاه في السياق والواجهة التشغيلية. يتم تمرير StreamProcessor (واجهة التشغيل) كمعلمة إلى طريقة ProcessStream () لـ StreamProcessorContext.
. IoException استثناء = فارغ ؛ حاول {int character = inputStream.Read () ؛ بينما (الحرف! = -1) {Processor.Process (حرف) ؛ حرف = inputStream.Read () ؛ }} أخيرًا {try {inputStream.close () ؛ } catch (ioException e) {if (issessive == null) throw e ؛ رمي الاستثناء }}}}يمكنك الآن استخدام فئة StreamProcessorContext لطباعة محتوى الدفق مثل المثال التالي:
FileInputStream inputStream = جديد fileInputStream ("myfile") ؛ // مثال على العملية من خلال تنفيذ الفئة الفرعية المجهولة لواجهة StreamProcessor الجديدة STREMPROCESSOXT (). processStream (inputStream ، New StreamProcessor ()أو اقرأ محتوى دفق الإدخال مثل هذا وأضفه إلى تسلسل الأحرف:
الفئة العامة StreamToStringReader تنفذ StreamProcessor {Private StringBuffer Buffer = جديد StringBuffer () ؛ Public StringBuffer getBuffer () {return this.buffer ؛ } عملية void العامة (int input) {this.buffer.append ((char) input) ؛ }} fileInputStream inputStream = جديد fileInputStream ("myfile") ؛ StreamToStringReader reader = new StreamToStringReader () ؛ New StreamProcessorContext (). ProcessStream (inputStream ، reader) ؛كما ترون ، افعل أي شيء مع الدفق عن طريق إدخال تطبيق واجهة StreamProcessor المختلفة. بمجرد تنفيذ StreamProcessorContext بالكامل ، لن تواجه أي مشكلة في التدفقات غير المغلقة.
إعادة استخدام السياق قوية للغاية ويمكن استخدامها في العديد من البيئات الأخرى خارج معالجة الدفق. تتمثل حالة الاستخدام الواضحة في التعامل مع اتصالات ومعاملات قاعدة البيانات بشكل صحيح ( open - process - commit()/rollback() - close() ). حالات الاستخدام الأخرى هي معالجة قناة NIO ومزامنة مؤشرات الترابط في الأقسام الحرجة ( lock() - access shared resource - unlock() ). يمكنه أيضًا تحويل الاستثناءات التي تم فحصها من API إلى استثناءات غير محددة.
عندما تبحث عن رمز مناسب لإعادة استخدام السياق في مشروعك ، ابحث عن أنماط التشغيل التالية:
عندما تجد مثل هذا النمط ، قد تحقق العمليات العادية قبل وبعد إعادة استخدام السياق.
السياق كوسيلة قالب
في بعض الأحيان ، سترغب في الحصول على نقاط إضافية متعددة في السياق. إذا كان السياق يتكون من العديد من الخطوات الأصغر وتريد أن تكون كل خطوة من السياق قابلة للتخصيص ، فيمكنك تنفيذ السياق كطريقة قالب. طريقة القالب هي نمط تصميم GOF. في الأساس ، تقسم طريقة القالب الخوارزمية أو البروتوكول إلى سلسلة من الخطوات. عادة ما يتم تنفيذ طريقة القالب كفئة قاعدة واحدة وتوفر طريقة لكل خطوة في خوارزمية أو بروتوكول. لتخصيص أي خطوة ، ما عليك سوى إنشاء فئة توسيع فئة قاعدة طريقة القالب وتجاوز طريقة الخطوة التي تريد تخصيصها.
المثال التالي هو JDBCContext الذي تم تنفيذه كطريقة قالب. يمكن للفئات الفرعية تجاوز فتح وإغلاق الاتصالات لتوفير سلوك مخصص. يجب دائمًا تجاوز طريقة ProcessRecord (نتائج ResultSet) لأنها مجردة. توفر هذه الطريقة عمليات غير موجودة في السياق وتختلف في حالات مختلفة باستخدام JDBCContext. هذا المثال ليس JDBCContext مثالي. يتم استخدامه فقط لإظهار كيفية استخدام طرق القالب عند تنفيذ السياق.
الفئة المجردة العامة jdbccontext {datasource dataSource = null ؛ // يمكن استخدام المُنشئ بدون معلمات للفئات الفرعية دون الحصول على بيانات DataSource للحصول على اتصال JDBCContext () {} public JDBCContext (DataSource DataSource) {this.datasource = dataSource ؛ } اتصال محمي OpenConnection () يلقي sqlexception {return datasource.getConnection () ؛ } محمية باطلة closeConnection (اتصال الاتصال) يلقي sqlexception {connection.close () ؛ }. Void public execute (String SQL ، Object [] parameters) يلقي sqlexception {connection connection = null ؛ استعداد بيان = فارغ ؛ نتيجة النتيجة = فارغة ؛ حاول {connection = openConnection () ؛ بيان = connection.preparestatement (SQL) ؛ لـ (int i = 0 ؛ i <parameters.length ؛ i ++) {state.setObject (i ، parameters [i]) ؛ } النتيجة = ittupe.executequery () ؛ بينما (result.next ()) {processRecord (result) ؛ }} أخيرًا {if (result! = null) {try {result.close () ؛ } catch (sqlexception e) { / * regnore * /}} if (state! = null) {try {state.close () ؛ } catch (sqlexception e) { / * regnore * /}} if (state! = null) {try {state.close () ؛ } catch (sqlexception e) { / * تجاهل * /}} if (connection! = null) {closeConnection (connection) ؛ }}}}هذه فئة فرعية تمتد JDBCContext لقراءة قائمة المستخدمين:
يمتد قراءات الفئة العامة JDBCContext {list users = new ArrayList () ؛ قراءات عامة (DataSource DataSource) {super (dataSource) ؛ } القائمة العامة getUsers () {return this.users ؛ } processRecord processRecord محمي (نتائج resultse) {user user = new user () ؛ user.setName (result.getString ("name")) ؛ user.setemail (result.getString ("email")) ؛ user.add (user) ؛ }}إليك كيفية استخدام فئة القراءة:
readusers readusers = new ensusers (dataSource) ؛ readUsers.execute ("SELECT * from users" ، compour new [0]) ؛ ers user user = readusers.getusers () ؛ إذا احتاجت فئة القراءات إلى الحصول على اتصال من تجمع الاتصال وإطلاقه إلى تجمع الاتصال بعد الاستخدام ، فيمكنك إدراج الاتصال عن طريق تجاوز أساليب openConnection() و closeConnection(Connection connection) .
لاحظ كيفية إعادة كتابة رمز تشغيل الإدراج من خلال الطريقة. تتجاوز الفئة الفرعية لـ JDBCContext طريقة ProcessRecord لتوفير معالجة سجل خاصة. في مثال StreamContext ، يتم تغليف رمز التشغيل في كائن منفصل ويتم توفيره كمعلمة طريقة. يتم تمرير الكائن الذي ينفذ معالج تشغيل واجهة التشغيل كمعلمة إلى طريقة ProcessStreamContext processStream(...) .
يمكنك استخدام كلا التقنيتين عند تنفيذ السياق. يمكن لفئة JDBCContext تمرير كائنات ConnectionOpener و ConnectionCloser التي تنفذ واجهة العملية كمعلمات إلى طريقة التنفيذ ، أو كمعلمات للمركبة. أنا شخصياً أفضل استخدام كائنات تشغيل منفصلة وواجهات تشغيل لسببين. أولاً ، يسهل اختبار وحدة التشغيل وحده ؛ ثانياً ، يجعل رمز التشغيل قابل لإعادة الاستخدام في سياقات متعددة. بالطبع ، يمكن أيضًا استخدام رمز التشغيل في أماكن متعددة في الكود ، ولكن هذه مجرد ميزة. بعد كل شيء ، نحن هنا نحاول فقط إعادة استخدام السياق ، وليس إعادة استخدام العمليات.
خاتمة
لقد رأيت الآن طريقتين مختلفتين لإعادة استخدام الكود. إعادة استخدام الميزة الكلاسيكية وإعادة استخدام السياق الأقل شيوعًا. نأمل أن تكون إعادة استخدام السياق شائعة مثل إعادة استخدام الميزة. يعد إعادة استخدام السياق طريقة مفيدة للغاية لرمز مجردة من التفاصيل الأساسية لواجهة برمجة التطبيقات (مثل JDBC أو IO أو NIO API ، إلخ). خاصة إذا كانت واجهة برمجة التطبيقات تحتوي على موارد يجب إدارتها (على وإغلاق ، احصل عليها والعودة ، إلخ).
يستخدم Mr.Persister Pressistence/ORM ، إعادة استخدام السياق لتحقيق اتصال تلقائي وإدارة دورة حياة المعاملات. وبهذه الطريقة ، لن يضطر المستخدم أبدًا للقلق بشأن فتح الاتصال أو إغلاقه بشكل صحيح ، أو ارتكاب المعاملة أو تراجعها. يوفر Mr.Persister سياقًا يمكن للمستخدمين فيه إدراج عملياتهم. هذه السياقات مسؤولة عن فتح وإغلاق وارتكاب وتراجع.
يحتوي إطار الربيع الشهير على الكثير من إعادة استخدام السياق. على سبيل المثال ينبع من التجريد JDBC. يستخدم مطورو الربيع أنه "انعكاس التحكم". ليس هذا هو نوع الانعكاس الوحيد للسيطرة المستخدمة بواسطة أطر الربيع. الميزة الأساسية في الربيع هي مصانع حبة الحقن التبعية أو "سياقات التطبيق". حقن التبعية هو نوع آخر من انعكاس التحكم.
ما ورد أعلاه هو إعادة استخدام الوظيفة والسياق لرمز Java الذي قدمه لك المحرر. آمل أن يكون ذلك مفيدًا لك. إذا كان لديك أي أسئلة ، فيرجى ترك رسالة لي وسوف يرد المحرر إليك في الوقت المناسب. شكرا جزيلا لدعمكم لموقع wulin.com!