English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

مثال شامل على نموذج النسخة في تصميم تطبيقات اندرويد

هذا المقال يشرح مثالًا على نموذج النسخ في تصميم البرمجة لـ Android. يُشارك الجميع للمراجعة، كما يلي:

أولًا، التعريف

نموذج النسخ هو نموذج إنشاء. كلمة ‘نسخ’ تشير إلى أن هذا النموذج يجب أن يكون لديه نموذج نموذجي، ويجب على المستخدم نسخ هذا النموذج لإنشاء كائن يحتوي على نفس الخصائص الداخلية، هذا العمل هو ما نسميه ‘نسخ’. الكائن المنسوخ هو ما نسميه ‘نموذج’. هذا النموذج قابل للتخصيص أيضًا. نموذج النسخ يستخدم غالبًا لإنشاء كائنات معقدة أو يتطلب بناءً مكلفًا، لأن في هذه الحالة، نسخ نموذج موجود يمكن أن يجعل تشغيل البرنامج أكثر كفاءة.

ثانيًا، التعريف

استخدام نموذج الم原型 لتعريف نوع الكائنات التي يتم إنشاؤها، ثم نسخ هذه النماذج لإنشاء كائنات جديدة.

ثالثًا، السيناريوهات الاستخدام

(1)类初始化需要消耗非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。

(2)通过new产生一个对象需要非常繁琐的数据准备或访问权限,这时可以使用原型模式。

(3)一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。

需要注意的是,通过实行Cloneable接口的原型模式在调用clone函数构造实例时并不一定比通过new操作速度快,只有当通过new构造对象较为耗时或者说成本较高时,通过clone方法才能够获得效率上的提升。因此,在使用Cloneable时需要考虑构建对象的成本以及做一些效率上的测试。当然,实现原型模式也不一定非要实现Cloneable接口,也有其他的实现方式,这里将会对这些一一说明。

四、原因模式的UML类图

图中规则介縫:

Client:客户端用户。

Prototype:抽象类或接口,告标有复制能力。

ConcretePrototype:实验的原因类。

五、原因模式简单实现

下面以简单的文档折复为例来演示简单的原因模式,我们在该个主要中首先创建了一个文档对象,即WordDocument,该文档中包含文字和图片。用户通过长时间的内容编辑后,想要对该文档做更较的编辑,但是,该编辑后的文档是否会被使用还未确定,因而,为了安公,用户需要将现有文档折一个,然后在文档备件上进行优化,这一样,该原始文档就是我们上述的模板实例,也就是将被“复制”的对象,我们叫以号每。

مثال على الكود:

/**
 * 文档类型,变佐是ConcretePrototype路径、而cloneable是表现prototype路径
 */
public class WordDocument implements Cloneable {
 //文本
 private String mText;
 //图片名列表
 private ArrayList<String> mImages = new ArrayList<String>();
 public WordDocument(){
  System.out.println("-------- WordDocument构造函数 --------");
 }
 public String getText(){
  return this.mText;
 }
 public void setText(String text){
  this.mText = text;
 }
 public ArrayList<String> getImages(){
  return this.mImages;
 }
 public void setImages(ArrayList<String> images){
  this.mImages = images;
 }
 public void addImage(String img){
  this.mImages.add(img);
 }
 /**
  * طباعة المستند
  */
 public void showDocument(){
  System.out.println("-------- بداية محتوى Word --------");
  System.out.println("نص : " + this.mText);
  System.out.println("قائمة الصور : ");
  for(String image : mImages){
   System.out.println("اسم الصورة : " + image);
  }
  System.out.println("-------- نهاية محتوى Word --------");
 }
 @Override
 protected WordDocument clone(){
  try{
   WordDocument doc = (WordDocument)super.clone();
   doc.mText = this.mText;
   doc.mImages = this.mImages;
   return doc;
  }얶catch(Exception e){}
  return null;
 }
}

تنفيذ العملية:

public static void main(String[] args) throws IOException {
  //1.بناء موضوع المستند
  WordDocument originDoc = new WordDocument();
  //2.تحرير المستند، إضافة صور إلخ
  originDoc.setText("هذا مستند");
  originDoc.addImage("صورة واحد");
  originDoc.addImage("صورة إثنين");
  originDoc.addImage("صورة ثلاثة");
  originDoc.showDocument();
  //بأصل المستند كنموذج، نسخة واحدة من البنية
  WordDocument doc2 = originDoc.clone();
  doc2.showDocument();
  //修改文档副本
  doc2.setText("这是修改过的Doc2文本");
  doc2.addImage("这是新添加的图片");
  originDoc.showDocument();
  doc2.showDocument();
}

执行结果:

-------- WordDocument构造函数 --------
//originDoc
-------- بداية محتوى Word --------
النص: هذا هو المستند
قائمة الصور:
اسم الصورة: الصورة الأولى
اسم الصورة: الصورة الثانية
اسم الصورة: الصورة الثالثة
-------- نهاية محتوى Word --------
//doc2
-------- بداية محتوى Word --------
النص: هذا هو المستند
قائمة الصور:
اسم الصورة: الصورة الأولى
اسم الصورة: الصورة الثانية
اسم الصورة: الصورة الثالثة
-------- نهاية محتوى Word --------
//تعديل النسخ الأصلي originDoc بعد النسخ
-------- بداية محتوى Word --------
النص: هذا هو المستند
قائمة الصور:
اسم الصورة: الصورة الأولى
اسم الصورة: الصورة الثانية
اسم الصورة: الصورة الثالثة
اسم الصورة: هذا هو الصورة المضافة حديثًا
-------- نهاية محتوى Word --------
//تعديل النسخ doc2 بعد النسخ
-------- بداية محتوى Word --------
النص: هذا هو النص المعدل في Doc2
قائمة الصور:
اسم الصورة: الصورة الأولى
اسم الصورة: الصورة الثانية
اسم الصورة: الصورة الثالثة
اسم الصورة: هذا هو الصورة المضافة حديثًا
-------- نهاية محتوى Word --------

这里我们发现通过修改doc2后,只是影响了originDoc的mImages,而没有改变mText。

六、浅拷贝和深拷贝

上述原型模式的实现实际上只是一个浅拷贝,也称影子拷贝,这份拷贝实际上并不是将原始的文档的所有字段都重新构造了一份,而是副本文档的字段引用原始文档的字段,如下图:

细心的读者又能从上面的结果中发现,最后两个文档信息出入是一相同的。我们在doc2添加了一张图片,但是,即使在originDoc中也展示了出来,这是哪么事情呢?学习过C++的读者都有比较深制的体验。因为上文中WordDocument的clone方法只是简单的转封复质。引用类型籾w对象doc2.mImages只是简单按照this.mImages引用。本来没有重构一个新的mImages对象。将原始文档中的图片添加到新的mImages对象中,就会成为这样:因而,doc2.mImages与原始文档中的是同一个对象,所以,修改了一个文档中的图片,其一个文档也会得到影响。那么怎么解决该问题呢?答案就是通过深复。在折复对象的时候,对引用类型的属数也要用折复的形式,而不是简单的引用的形式。

clone方法修改如下(其他不变):

@Override
protected WordDocument clone(){
  try{
   WordDocument doc = (WordDocument)super.clone();
   doc.mText = this.mText;
   //对mImages对象也调用clone()函数,进行深复复
   doc.mImages = (ArrayList<String>)this.mImages.clone();
   return doc;
  }얶catch(Exception e){}
  return null;
}

޸后在执行上述代码的结果是:

-------- WordDocument构造函数 --------
//originDoc
-------- بداية محتوى Word --------
النص: هذا هو المستند
قائمة الصور:
اسم الصورة: الصورة الأولى
اسم الصورة: الصورة الثانية
اسم الصورة: الصورة الثالثة
-------- نهاية محتوى Word --------
//doc2
-------- بداية محتوى Word --------
النص: هذا هو المستند
قائمة الصور:
اسم الصورة: الصورة الأولى
اسم الصورة: الصورة الثانية
اسم الصورة: الصورة الثالثة
-------- نهاية محتوى Word --------
//تعديل النسخ الأصلي originDoc بعد النسخ
-------- بداية محتوى Word --------
النص: هذا هو المستند
قائمة الصور:
اسم الصورة: الصورة الأولى
اسم الصورة: الصورة الثانية
اسم الصورة: الصورة الثالثة
-------- نهاية محتوى Word --------
//تعديل النسخ doc2 بعد النسخ
-------- بداية محتوى Word --------
النص: هذا هو النص المعدل في Doc2
قائمة الصور:
اسم الصورة: الصورة الأولى
اسم الصورة: الصورة الثانية
اسم الصورة: الصورة الثالثة
اسم الصورة: هذا هو الصورة المضافة حديثًا
-------- نهاية محتوى Word --------

يظهر الآن أنهما لا يؤثران على بعضهما البعض، ويُدعى هذا النسخ العميق.

بعد ذلك، في الواقع، عند النسخ السطحي لـ String، يشبه النوع المشار إليه النوع المشار إليه، لا يتم نسخه بشكل منفرد، بل يتم استخدامه كمرجع لنفس العنوان، لأن String لم يحقق واجهة cloneable، مما يعني أنه يمكن نسخ المرجع فقط. (يمكننا النظر في الشيفرة المصدر لرؤية ذلك، بينما قام ArrayList بتحقيق واجهة cloneable). ولكن عندما يتم تعديل إحدى القيم، يتم تخصيص مساحة ذاكرة جديدة لتخزين القيمة الجديدة، ويشير المرجع إلى مساحة الذاكرة الجديدة، بينما لا يتم إزالة String لأنه لا يزال يحتوي على مرجع يوجه إليه، لذا، على الرغم من أن المرجع تم نسخه، إلا أن تعديل القيمة لا يؤثر على قيمة العنصر المنسوخ.

لذلك، في العديد من الحالات، يمكن معالجة String بنفس الطريقة عند النسخ وكذلك الأنواع الأساسية، فقط يجب الانتباه إلى بعض الأمور عند استخدام equals.

نموذج النسخ هو نموذج بسيط للغاية، ويتمثل جوهره في نسخ العنصر الأصلي، وهو شيء يجب الانتباه إليه أثناء استخدام هذا النموذج: مشكلة النسخ العميق والنسخ الواسع. أثناء عملية البرمجة، لمنع ارتكاب الأخطاء، يوصي الكاتب باستخدام هذا النموذج بأقصى قدر ممكن من النسخ العميق لتجنب مشكلة التأثير على العنصر الأصلي عند تعديل النسخ.

نموذج النسخ في رمز Android

مثال على الكود:

Uri uri = Uri.parse("smsto:110");
Intent intent = new Intent(Intent.ACTION_SEND,uri);
intent.putExtra("sms_body", "The SMS text");
//نسخ
Intent intent2 = (Intent)intent.clone();
startActivity(intent2);

النتيجة العامة

نموذج النسخ الأساسي هو نسخ العناصر، يشبه بعض الشيء مبدأ بناء الكوبيات في C++، والمشاكل التي يمكن أن تحدث بينهما هي نسخ عميق ونسخ واسع. يمكن استخدام نموذج النسخ لحل مشكلة استهلاك الموارد في بناء العناصر المعقدة، ويمكن أن يزيد من كفاءة إنشاء العناصر في بعض السيناريوهات.

القوة:

(1) نموذجPrototype هو نسخة ثنائية في الذاكرة، وهو أفضل بكثير من إنشاء مكون جديد باستخدام new، خاصة عند إنشاء العديد من المكونات في حلقة، قد يظهر نموذجPrototype مزاياها بشكل أفضل.

(2) هناك استخدام مهم آخر وهو النسخ الحماية، أي أن بعض العناصر قد تكون قابلة للقراءة فقط من الخارج، من أجل منع تعديل العنصر القابل للقراءة من الخارج، عادة ما يتم تحقيق القيود القابلة للقراءة من خلال إرجاع نسخة من العنصر.

الضعف:

(1) هذا هو قوته أيضًا وضعفه، التكثيف المباشر في الذاكرة، لا يتم تنفيذ بناء المكونات، يجب الانتباه لهذه المشكلة المحتملة في التطوير العملي. الضعف هو تقليل القيود، والضعف أيضًا هو تقليل القيود، يجب أن يفكر الجميع في ذلك عند التطبيق العملي.

(2) لا يتأكد أن نموذجPrototype، الذي يتم إنشاؤه عن طريق تنفيذ واجهة Cloneable، يكون أسرع في التشغيل عند استدعاء دالة clone بناءً على بناء المثال، مقارنة باستخدام عملية new، فقط عندما يكون إنشاء المثال باستخدام new مكلفًا أو مكلفًا، يمكن أن يحقق clone تحسينًا في الكفاءة.

للمزيد من المعلومات المتعلقة بAndroid، يمكن للقراء المهتمين التحقق من مواضيع هذا الموقع: 'دليل البدء والتحسين في تطوير Android'، 'أساليب الت调试 والتغلب على المشاكل الشائعة في Android'، 'تجميع استخدامات العناصر الأساسية في Android'، 'تجميع تقنيات عرض View في Android'، 'تجميع تقنيات تصميم التخطيط Layout في Android'، و 'تجميع استخدامات العناصر التحكم في Android'.

آمل أن يساعدك هذا المقال في تصميم برامج Android.

بيان: محتوى هذا المقال تم جمعه من الإنترنت، وله حقوق الملكية الأصلية للمالك، تم جمع المحتوى من قبل المستخدمين على الإنترنت بطرقهم الخاصة، ويحمل هذا الموقع حقوق الملكية، لم يتم تعديل المحتوى بشكل يدوي، ولا يتحمل هذا الموقع أي مسؤولية قانونية. إذا وجدت محتوى يشتبه في انتهاك حقوق النسخ، فلا تتردد في إرسال بريد إلكتروني إلى: notice#oldtoolbag.com (عند إرسال البريد الإلكتروني، يرجى استبدال # ب @) لتقديم الشكوى، وتقديم الدليل المتعلق، إذا تم التحقق من ذلك، فإن هذا الموقع سيزيل محتوى يشتبه في انتهاك حقوق النسخ فورًا.

أنت قد تحب