---
title: "النموذج الأولي (Prototype)"
type: "design-pattern"
slug: "prototype"
url: "http://localhost:3000/ar/design-patterns/prototype.md"
category: "الأنماط الإنشائية"
description: "النموذج الأولي (Prototype) هو نمط تصميم إبداعي يتيح لك نسخ الكائنات الموجودة دون جعل كودك يعتمد على فئاتها."
languages: ["java", "csharp", "cpp", "go", "php", "python", "ruby", "rust", "swift", "typescript"]
---
# النموذج الأولي (Prototype)

> النموذج الأولي (Prototype) هو نمط تصميم إبداعي يتيح لك نسخ الكائنات الموجودة دون جعل كودك يعتمد على فئاتها.

## Intent

**Prototype** is a creational design pattern that lets you copy existing objects without making your code dependent on their classes.

## Problem

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

رائع! لكن هناك مشكلة. لا يمكن نسخ جميع الكائنات بهذه الطريقة لأن بعض حقول الكائن قد تكون خاصة وغير مرئية من خارج الكائن نفسه.

نسخ الكائن "من الخارج" [ليس](/ar/antipatterns/cargo-cult-programming) ممكنًا دائمًا.

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

## Solution

يُفوِّض نمط النموذج الأولي عملية الاستنساخ إلى الكائنات الفعلية التي يتم استنساخها. يُعلن النمط عن واجهة مشتركة لجميع الكائنات التي تدعم الاستنساخ. تتيح هذه الواجهة استنساخ كائن دون ربط كودك بفئة ذلك الكائن. عادةً، تحتوي مثل هذه الواجهة على طريقة واحدة فقط وهي `clone`.

يتشابه تنفيذ طريقة `clone` كثيرًا في جميع الفئات. تُنشئ الطريقة كائنًا من الفئة الحالية وتنقل إليه جميع قيم حقول الكائن القديم. يمكنك حتى نسخ الحقول الخاصة لأن معظم لغات البرمجة تتيح للكائنات الوصول إلى الحقول الخاصة لكائنات أخرى تنتمي إلى نفس الفئة.

يُسمى الكائن الذي يدعم الاستنساخ _نموذجًا أوليًا_. عندما تحتوي كائناتك على عشرات الحقول ومئات التكوينات الممكنة، قد يكون استنساخها بديلاً للتصنيف الفرعي.

يمكن أن تكون النماذج الأولية المبنية مسبقًا بديلاً للتصنيف الفرعي.

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

## Structure

#### التنفيذ الأساسي

1. تُعلن واجهة **Prototype** عن طرق الاستنساخ. في معظم الحالات تكون طريقة `clone` واحدة فقط.
2. تُنفِّذ فئة **Concrete Prototype** طريقة الاستنساخ. بالإضافة إلى نسخ بيانات الكائن الأصلي إلى النسخة، قد تعالج هذه الطريقة أيضًا بعض الحالات الحدية لعملية الاستنساخ المتعلقة باستنساخ الكائنات المرتبطة وفك التشابك من التبعيات العودية وما إلى ذلك.
3. يمكن لـ **Client** إنتاج نسخة من أي كائن يتبع واجهة النموذج الأولي.

#### تنفيذ سجل النماذج الأولية

1. يوفر **Prototype Registry** طريقة سهلة للوصول إلى النماذج الأولية المستخدمة بشكل متكرر. يُخزِّن مجموعة من الكائنات المبنية مسبقًا الجاهزة للنسخ. أبسط سجل للنماذج الأولية هو خريطة تجزئة `name → prototype`. ومع ذلك، إذا كنت بحاجة إلى معايير بحث أفضل من مجرد اسم، يمكنك بناء نسخة أكثر قوة من السجل.

## Pseudocode

في هذا المثال، يتيح لك نمط **النموذج الأولي (Prototype)** إنتاج نسخ طبق الأصل من الكائنات الهندسية دون ربط الكود بفئاتها.

Cloning a set of objects that belong to a class hierarchy.

All shape classes follow the same interface, which provides a cloning method. A subclass may call the parent’s cloning method before copying its own field values to the resulting object.

// النموذج الأولي الأساسي.
abstract class Shape is
    field X: int
    field Y: int
    field color: string

    // مُنشئ عادي.
    constructor Shape() is
        // ...

    // مُنشئ النموذج الأولي. يُهيَّأ كائن جديد
    // بقيم من الكائن الموجود.
    constructor Shape(source: Shape) is
        this()
        this.X = source.X
        this.Y = source.Y
        this.color = source.color

    // تُعيد عملية الاستنساخ إحدى الفئات الفرعية من Shape.
    abstract method clone():Shape

// النموذج الأولي المحدد. تُنشئ طريقة الاستنساخ كائنًا جديدًا
// دفعةً واحدة عن طريق استدعاء مُنشئ الفئة الحالية و
// تمرير الكائن الحالي كمعامل للمُنشئ.
// إجراء جميع عمليات النسخ الفعلية في المُنشئ يساعد على
// الحفاظ على تناسق النتيجة: لن يُعيد المُنشئ
// نتيجة حتى يُبنى الكائن الجديد بالكامل؛ وبالتالي لا يوجد كائن
// يمكنه الإشارة إلى نسخة مبنية جزئيًا.
class Rectangle extends Shape is
    field width: int
    field height: int

    constructor Rectangle(source: Rectangle) is
        // استدعاء المُنشئ الأصلي ضروري لنسخ الحقول الخاصة
        // المُعرَّفة في الفئة الأصلية.
        super(source)
        this.width = source.width
        this.height = source.height

    method clone():Shape is
        return new Rectangle(this)

class Circle extends Shape is
    field radius: int

    constructor Circle(source: Circle) is
        super(source)
        this.radius = source.radius

    method clone():Shape is
        return new Circle(this)

// في مكان ما في كود العميل.
class Application is
    field shapes: array of Shape

    constructor Application() is
        Circle circle = new Circle()
        circle.X = 10
        circle.Y = 10
        circle.radius = 20
        shapes.add(circle)

        Circle anotherCircle = circle.clone()
        shapes.add(anotherCircle)
        // يحتوي المتغير `anotherCircle` على نسخة طبق الأصل
        // من كائن `circle`.

        Rectangle rectangle = new Rectangle()
        rectangle.width = 10
        rectangle.height = 20
        shapes.add(rectangle)

    method businessLogic() is
        // النموذج الأولي رائع لأنه يتيح لك إنتاج نسخة من
        // كائن دون معرفة أي شيء عن نوعه.
        Array shapesCopy = new Array of Shapes.

        // على سبيل المثال، لا نعرف العناصر الدقيقة في مصفوفة
        // الأشكال. كل ما نعرفه أنها جميعها
        // أشكال. لكن بفضل تعدد الأشكال، عند استدعاء طريقة
        // `clone` على شكل ما يتحقق البرنامج من فئته الحقيقية
        // ويشغّل طريقة الاستنساخ المناسبة المُعرَّفة
        // في تلك الفئة. لهذا السبب نحصل على نسخ صحيحة
        // بدلاً من مجموعة من كائنات Shape البسيطة.
        foreach (s in shapes) do
            shapesCopy.add(s.clone())

        // تحتوي مصفوفة `shapesCopy` على نسخ طبق الأصل من
        // عناصر مصفوفة `shape`.

## Applicability

استخدم نمط النموذج الأولي عندما لا ينبغي لكودك الاعتماد على الفئات المحددة للكائنات التي تحتاج إلى نسخها.

 يحدث هذا كثيرًا عندما يعمل كودك مع كائنات تُمرَّر إليك من كود طرف ثالث عبر واجهة ما. الفئات المحددة لهذه الكائنات غير معروفة، ولا يمكنك الاعتماد عليها حتى لو أردت ذلك.

يوفر نمط النموذج الأولي لكود العميل واجهة عامة للعمل مع جميع الكائنات التي تدعم الاستنساخ. تجعل هذه الواجهة كود العميل مستقلاً عن الفئات المحددة للكائنات التي يستنسخها.

 استخدم النمط عندما تريد تقليل عدد الفئات الفرعية التي تختلف فقط في طريقة تهيئة كائناتها المعنية.

 لنفترض أن لديك فئة معقدة تتطلب تهيئة شاقة قبل أن تتمكن من استخدامها. هناك عدة طرق شائعة لتهيئة هذه الفئة، وهذا الكود منتشر في جميع أنحاء تطبيقك. لتقليل التكرار، تُنشئ عدة فئات فرعية وتضع كل كود التهيئة الشائع في مُنشئاتها. لقد حللت مشكلة التكرار، لكن أصبح لديك الآن كثير من الفئات الفرعية الوهمية.

يتيح لك نمط النموذج الأولي استخدام مجموعة من الكائنات المبنية مسبقًا والمُهيَّأة بطرق مختلفة كنماذج أولية. بدلاً من تهيئة فئة فرعية تتطابق مع تهيئة معينة، يمكن للعميل ببساطة البحث عن نموذج أولي مناسب واستنساخه.

## How to Implement

1. أنشئ واجهة النموذج الأولي وأعلن عن طريقة `clone` فيها. أو فقط أضف الطريقة إلى جميع فئات تدرج هرمي موجود للفئات إذا كان لديك واحد.
2. يجب أن تُعرِّف فئة النموذج الأولي المُنشئ البديل الذي يقبل كائنًا من تلك الفئة كمعامل. يجب أن ينسخ المُنشئ قيم جميع الحقول المُعرَّفة في الفئة من الكائن المُمرَّر إلى النسخة المُنشأة حديثًا. إذا كنت تُعدِّل فئة فرعية، يجب أن تستدعي المُنشئ الأصلي للسماح للفئة الأعلى بمعالجة استنساخ حقولها الخاصة.
إذا كانت لغة البرمجة لا تدعم تحميل الدوال الزائد (method overloading)، لن تتمكن من إنشاء مُنشئ "نموذج أولي" منفصل. وبالتالي ستُنفَّذ عملية نسخ بيانات الكائن إلى النسخة المستنسخة المنشأة حديثًا داخل طريقة `clone`. ومع ذلك، وجود هذا الكود في مُنشئ عادي أكثر أمانًا لأن الكائن الناتج يُعاد مُهيَّأ بالكامل مباشرةً بعد استدعاء عامل `new`.
3. تتكون طريقة الاستنساخ عادةً من سطر واحد فقط: تشغيل عامل `new` مع نسخة النموذج الأولي من المُنشئ. لاحظ أن كل فئة يجب أن تُجاوز طريقة الاستنساخ صراحةً وتستخدم اسم فئتها الخاص مع عامل `new`. وإلا قد تُنتج طريقة الاستنساخ كائنًا من الفئة الأصلية.
4. اختياريًا، أنشئ سجل نماذج أولية مركزيًا لتخزين كتالوج من النماذج الأولية المستخدمة بشكل متكرر.
يمكنك تنفيذ السجل كفئة مصنع جديدة أو وضعه في فئة النموذج الأولي الأساسية مع طريقة ثابتة لجلب النموذج الأولي. يجب أن تبحث هذه الطريقة عن نموذج أولي بناءً على معايير البحث التي يمررها كود العميل إلى الطريقة. يمكن أن تكون المعايير إما علامة نصية بسيطة أو مجموعة معقدة من معاملات البحث. بعد العثور على النموذج الأولي المناسب، يجب على السجل استنساخه وإرجاع النسخة إلى العميل.
أخيرًا، استبدل الاستدعاءات المباشرة لمُنشئات الفئات الفرعية باستدعاءات لطريقة المصنع في سجل النماذج الأولية.

## Pros

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

## Cons

* قد يكون استنساخ الكائنات المعقدة التي تحتوي على مراجع دائرية أمرًا بالغ التعقيد.

## Relations with Other Patterns

* تبدأ العديد من التصميمات باستخدام [Factory Method](/ar/design-patterns/factory-method) (أقل تعقيداً وأكثر قابلية للتخصيص عبر الفئات الفرعية) وتتطور نحو [Abstract Factory](/ar/design-patterns/abstract-factory)، أو [Prototype](/ar/design-patterns/prototype)، أو [Builder](/ar/design-patterns/builder) (أكثر مرونة، ولكن أكثر تعقيداً).
* غالباً ما تعتمد فئات [Abstract Factory](/ar/design-patterns/abstract-factory) على مجموعة من [Factory Methods](/ar/design-patterns/factory-method)، ولكن يمكنك أيضاً استخدام [Prototype](/ar/design-patterns/prototype) لتركيب الدوال على هذه الفئات.
* يمكن أن يساعد [Prototype](/ar/design-patterns/prototype) عندما تحتاج إلى حفظ نسخ من [Commands](/ar/design-patterns/command) في السجل.
* التصميمات التي تستخدم [Composite](/ar/design-patterns/composite) و[Decorator](/ar/design-patterns/decorator) بشكل مكثف يمكنها في كثير من الأحيان الاستفادة من استخدام [Prototype](/ar/design-patterns/prototype). يتيح لك تطبيق النمط استنساخ هياكل معقدة بدلاً من إعادة بنائها من الصفر.
* لا يعتمد [Prototype](/ar/design-patterns/prototype) على الوراثة لذلك لا يعاني من عيوبها. من ناحية أخرى، يتطلب _Prototype_ تهيئة معقدة للكائن المستنسخ. يعتمد [Factory Method](/ar/design-patterns/factory-method) على الوراثة لكنه لا يتطلب خطوة تهيئة.
* أحياناً يمكن أن يكون [Prototype](/ar/design-patterns/prototype) بديلاً أبسط لـ [Memento](/ar/design-patterns/memento). يعمل هذا إذا كان الكائن الذي تريد تخزين حالته في السجل بسيطًا نسبيًا ولا يحتوي على روابط لموارد خارجية، أو كانت الروابط سهلة الإعادة.
* يمكن تنفيذ كل من [Abstract Factories](/ar/design-patterns/abstract-factory) و[Builders](/ar/design-patterns/builder) و[Prototypes](/ar/design-patterns/prototype) كـ [Singletons](/ar/design-patterns/singleton).
## Relations

**Related patterns**

- [طريقة المصنع](/ar/design-patterns/factory-method.md)
- [المصنع المجرد (Abstract Factory)](/ar/design-patterns/abstract-factory.md)
- [البنّاء](/ar/design-patterns/builder.md)
- [الأمر (Command)](/ar/design-patterns/command.md)
- [المركَّب](/ar/design-patterns/composite.md)
- [المُزَخرِف](/ar/design-patterns/decorator.md)
- [التذكار](/ar/design-patterns/memento.md)
- [Singleton](/ar/design-patterns/singleton.md)

## Code Examples

### java

```java
package refactoring_guru.prototype.example.shapes;

import java.util.Objects;

public abstract class Shape {
    public int x;
    public int y;
    public String color;

    public Shape() {
    }

    public Shape(Shape target) {
        if (target != null) {
            this.x = target.x;
            this.y = target.y;
            this.color = target.color;
        }
    }

    public abstract Shape clone();

    @Override
    public boolean equals(Object object2) {
        if (!(object2 instanceof Shape)) return false;
        Shape shape2 = (Shape) object2;
        return shape2.x == x && shape2.y == y && Objects.equals(shape2.color, color);
    }
}

package refactoring_guru.prototype.example.shapes;

public class Circle extends Shape {
    public int radius;

    public Circle() {
    }

    public Circle(Circle target) {
        super(target);
        if (target != null) {
            this.radius = target.radius;
        }
    }

    @Override
    public Shape clone() {
        return new Circle(this);
    }

    @Override
    public boolean equals(Object object2) {
        if (!(object2 instanceof Circle) || !super.equals(object2)) return false;
        Circle shape2 = (Circle) object2;
        return shape2.radius == radius;
    }
}

package refactoring_guru.prototype.example.shapes;

public class Rectangle extends Shape {
    public int width;
    public int height;

    public Rectangle() {
    }

    public Rectangle(Rectangle target) {
        super(target);
        if (target != null) {
            this.width = target.width;
            this.height = target.height;
        }
    }

    @Override
    public Shape clone() {
        return new Rectangle(this);
    }

    @Override
    public boolean equals(Object object2) {
        if (!(object2 instanceof Rectangle) || !super.equals(object2)) return false;
        Rectangle shape2 = (Rectangle) object2;
        return shape2.width == width && shape2.height == height;
    }
}

package refactoring_guru.prototype.example;

import refactoring_guru.prototype.example.shapes.Circle;
import refactoring_guru.prototype.example.shapes.Rectangle;
import refactoring_guru.prototype.example.shapes.Shape;

import java.util.ArrayList;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<Shape> shapes = new ArrayList<>();
        List<Shape> shapesCopy = new ArrayList<>();

        Circle circle = new Circle();
        circle.x = 10;
        circle.y = 20;
        circle.radius = 15;
        circle.color = "red";
        shapes.add(circle);

        Circle anotherCircle = (Circle) circle.clone();
        shapes.add(anotherCircle);

        Rectangle rectangle = new Rectangle();
        rectangle.width = 10;
        rectangle.height = 20;
        rectangle.color = "blue";
        shapes.add(rectangle);

        cloneAndCompare(shapes, shapesCopy);
    }

    private static void cloneAndCompare(List<Shape> shapes, List<Shape> shapesCopy) {
        for (Shape shape : shapes) {
            shapesCopy.add(shape.clone());
        }

        for (int i = 0; i < shapes.size(); i++) {
            if (shapes.get(i) != shapesCopy.get(i)) {
                System.out.println(i + ": Shapes are different objects (yay!)");
                if (shapes.get(i).equals(shapesCopy.get(i))) {
                    System.out.println(i + ": And they are identical (yay!)");
                } else {
                    System.out.println(i + ": But they are not identical (booo!)");
                }
            } else {
                System.out.println(i + ": Shape objects are the same (booo!)");
            }
        }
    }
}

0: Shapes are different objects (yay!)
0: And they are identical (yay!)
1: Shapes are different objects (yay!)
1: And they are identical (yay!)
2: Shapes are different objects (yay!)
2: And they are identical (yay!)

package refactoring_guru.prototype.caching.cache;

import refactoring_guru.prototype.example.shapes.Circle;
import refactoring_guru.prototype.example.shapes.Rectangle;
import refactoring_guru.prototype.example.shapes.Shape;

import java.util.HashMap;
import java.util.Map;

public class BundledShapeCache {
    private Map<String, Shape> cache = new HashMap<>();

    public BundledShapeCache() {
        Circle circle = new Circle();
        circle.x = 5;
        circle.y = 7;
        circle.radius = 45;
        circle.color = "Green";

        Rectangle rectangle = new Rectangle();
        rectangle.x = 6;
        rectangle.y = 9;
        rectangle.width = 8;
        rectangle.height = 10;
        rectangle.color = "Blue";

        cache.put("Big green circle", circle);
        cache.put("Medium blue rectangle", rectangle);
    }

    public Shape put(String key, Shape shape) {
        cache.put(key, shape);
        return shape;
    }

    public Shape get(String key) {
        return cache.get(key).clone();
    }
}

package refactoring_guru.prototype.caching;

import refactoring_guru.prototype.caching.cache.BundledShapeCache;
import refactoring_guru.prototype.example.shapes.Shape;

public class Demo {
    public static void main(String[] args) {
        BundledShapeCache cache = new BundledShapeCache();

        Shape shape1 = cache.get("Big green circle");
        Shape shape2 = cache.get("Medium blue rectangle");
        Shape shape3 = cache.get("Medium blue rectangle");

        if (shape1 != shape2 && !shape1.equals(shape2)) {
            System.out.println("Big green circle != Medium blue rectangle (yay!)");
        } else {
            System.out.println("Big green circle == Medium blue rectangle (booo!)");
        }

        if (shape2 != shape3) {
            System.out.println("Medium blue rectangles are two different objects (yay!)");
            if (shape2.equals(shape3)) {
                System.out.println("And they are identical (yay!)");
            } else {
                System.out.println("But they are not identical (booo!)");
            }
        } else {
            System.out.println("Rectangle objects are the same (booo!)");
        }
    }
}

Big green circle != Medium blue rectangle (yay!)
Medium blue rectangles are two different objects (yay!)
And they are identical (yay!)
```

### csharp

```csharp
using System;

namespace RefactoringGuru.DesignPatterns.Prototype.Conceptual
{
    public class Person
    {
        public int Age;
        public DateTime BirthDate;
        public string Name;
        public IdInfo IdInfo;

        public Person ShallowCopy()
        {
            return (Person) this.MemberwiseClone();
        }

        public Person DeepCopy()
        {
            Person clone = (Person) this.MemberwiseClone();
            clone.IdInfo = new IdInfo(IdInfo.IdNumber);
            clone.Name = String.Copy(Name);
            return clone;
        }
    }

    public class IdInfo
    {
        public int IdNumber;

        public IdInfo(int idNumber)
        {
            this.IdNumber = idNumber;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            p1.Age = 42;
            p1.BirthDate = Convert.ToDateTime("1977-01-01");
            p1.Name = "Jack Daniels";
            p1.IdInfo = new IdInfo(666);

            // تنفيذ نسخة سطحية من p1 وتعيينها إلى p2.
            Person p2 = p1.ShallowCopy();
            // إجراء نسخة عميقة من p1 وتعيينها إلى p3.
            Person p3 = p1.DeepCopy();

            // عرض قيم p1 و p2 و p3.
            Console.WriteLine("Original values of p1, p2, p3:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p2 instance values:");
            DisplayValues(p2);
            Console.WriteLine("   p3 instance values:");
            DisplayValues(p3);

            // تغيير قيم خصائص p1 وعرض قيم p1،
            // p2 و p3.
            p1.Age = 32;
            p1.BirthDate = Convert.ToDateTime("1900-01-01");
            p1.Name = "Frank";
            p1.IdInfo.IdNumber = 7878;
            Console.WriteLine("\nValues of p1, p2 and p3 after changes to p1:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p2 instance values (reference values have changed):");
            DisplayValues(p2);
            Console.WriteLine("   p3 instance values (everything was kept the same):");
            DisplayValues(p3);
        }

        public static void DisplayValues(Person p)
        {
            Console.WriteLine("      Name: {0:s}, Age: {1:d}, BirthDate: {2:MM/dd/yy}",
                p.Name, p.Age, p.BirthDate);
            Console.WriteLine("      ID#: {0:d}", p.IdInfo.IdNumber);
        }
    }
}

Original values of p1, p2, p3:
   p1 instance values: 
      Name: Jack Daniels, Age: 42, BirthDate: 01/01/77
      ID#: 666
   p2 instance values:
      Name: Jack Daniels, Age: 42, BirthDate: 01/01/77
      ID#: 666
   p3 instance values:
      Name: Jack Daniels, Age: 42, BirthDate: 01/01/77
      ID#: 666

Values of p1, p2 and p3 after changes to p1:
   p1 instance values: 
      Name: Frank, Age: 32, BirthDate: 01/01/00
      ID#: 7878
   p2 instance values (reference values have changed):
      Name: Jack Daniels, Age: 42, BirthDate: 01/01/77
      ID#: 7878
   p3 instance values (everything was kept the same):
      Name: Jack Daniels, Age: 42, BirthDate: 01/01/77
      ID#: 666
```

### cpp

```cpp
using std::string;

// نمط تصميم النموذج الأولي
//
// الغرض: يتيح لك نسخ الكائنات الموجودة دون جعل كودك يعتمد على
// فئاتها.

enum Type {
  PROTOTYPE_1 = 0,
  PROTOTYPE_2
};

/**
 * فئة المثال التي تمتلك قدرة الاستنساخ. سنرى كيف يتم استنساخ قيم الحقول
 * التي تحتوي على أنواع مختلفة.
 */

class Prototype {
 protected:
  string prototype_name_;
  float prototype_field_;

 public:
  Prototype() {}
  Prototype(string prototype_name)
      : prototype_name_(prototype_name) {
  }
  virtual ~Prototype() {}
  virtual Prototype *Clone() const = 0;
  virtual void Method(float prototype_field) {
    this->prototype_field_ = prototype_field;
    std::cout << "Call Method from " << prototype_name_ << " with field : " << prototype_field << std::endl;
  }
};

/**
 * ConcretePrototype1 هي فئة فرعية من Prototype وتُنفِّذ طريقة Clone.
 * في هذا المثال جميع أعضاء بيانات فئة Prototype موجودون في المكدس. إذا كان
 * لديك مؤشرات في خصائصك مثل: String* name_، ستحتاج إلى
 * تنفيذ مُنشئ النسخ للتأكد من الحصول على نسخة عميقة من
 * طريقة الاستنساخ.
 */

class ConcretePrototype1 : public Prototype {
 private:
  float concrete_prototype_field1_;

 public:
  ConcretePrototype1(string prototype_name, float concrete_prototype_field)
      : Prototype(prototype_name), concrete_prototype_field1_(concrete_prototype_field) {
  }

  /**
   * لاحظ أن طريقة Clone تُعيد مؤشرًا إلى نسخة جديدة من ConcretePrototype1.
   * لذا يتحمل العميل (الذي يستدعي طريقة clone) مسؤولية
   * تحرير تلك الذاكرة. إذا كنت تمتلك معرفة بالمؤشرات الذكية، قد تفضّل
   * استخدام unique_pointer هنا.
   */
  Prototype *Clone() const override {
    return new ConcretePrototype1(*this);
  }
};

class ConcretePrototype2 : public Prototype {
 private:
  float concrete_prototype_field2_;

 public:
  ConcretePrototype2(string prototype_name, float concrete_prototype_field)
      : Prototype(prototype_name), concrete_prototype_field2_(concrete_prototype_field) {
  }
  Prototype *Clone() const override {
    return new ConcretePrototype2(*this);
  }
};

/**
 * في PrototypeFactory لديك نموذجان أوليان محددان، واحد لكل
 * فئة نموذج أولي محدد، وبالتالي في كل مرة تريد إنشاء عنصر يمكنك
 * استخدام الكائنات الموجودة واستنساخها.
 */

class PrototypeFactory {
 private:
  std::unordered_map<Type, Prototype *, std::hash<int>> prototypes_;

 public:
  PrototypeFactory() {
    prototypes_[Type::PROTOTYPE_1] = new ConcretePrototype1("PROTOTYPE_1 ", 50.f);
    prototypes_[Type::PROTOTYPE_2] = new ConcretePrototype2("PROTOTYPE_2 ", 60.f);
  }

  /**
   * انتبه إلى تحرير جميع الذاكرة المخصصة. مجددًا، إذا كانت لديك معرفة
   * بالمؤشرات الذكية سيكون من الأفضل استخدامها هنا.
   */

  ~PrototypeFactory() {
    delete prototypes_[Type::PROTOTYPE_1];
    delete prototypes_[Type::PROTOTYPE_2];
  }

  /**
   * لاحظ هنا أنك تحتاج فقط إلى تحديد نوع النموذج الأولي الذي
   * تريده وستقوم الطريقة بالإنشاء من الكائن بهذا النوع.
   */
  Prototype *CreatePrototype(Type type) {
    return prototypes_[type]->Clone();
  }
};

void Client(PrototypeFactory &prototype_factory) {
  std::cout << "Let's create a Prototype 1\n";

  Prototype *prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_1);
  prototype->Method(90);
  delete prototype;

  std::cout << "\n";

  std::cout << "Let's create a Prototype 2 \n";

  prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_2);
  prototype->Method(10);

  delete prototype;
}

int main() {
  PrototypeFactory *prototype_factory = new PrototypeFactory();
  Client(*prototype_factory);
  delete prototype_factory;

  return 0;
}

Let's create a Prototype 1
Call Method from PROTOTYPE_1  with field : 90

Let's create a Prototype 2 
Call Method from PROTOTYPE_2  with field : 10
```

### go

```go
package main

type Inode interface {
	print(string)
	clone() Inode
}

package main

import "fmt"

type File struct {
	name string
}

func (f *File) print(indentation string) {
	fmt.Println(indentation + f.name)
}

func (f *File) clone() Inode {
	return &File{name: f.name + "_clone"}
}

package main

import "fmt"

type Folder struct {
	children []Inode
	name     string
}

func (f *Folder) print(indentation string) {
	fmt.Println(indentation + f.name)
	for _, i := range f.children {
		i.print(indentation + indentation)
	}
}

func (f *Folder) clone() Inode {
	cloneFolder := &Folder{name: f.name + "_clone"}
	var tempChildren []Inode
	for _, i := range f.children {
		copy := i.clone()
		tempChildren = append(tempChildren, copy)
	}
	cloneFolder.children = tempChildren
	return cloneFolder
}

package main

import "fmt"

func main() {
	file1 := &File{name: "File1"}
	file2 := &File{name: "File2"}
	file3 := &File{name: "File3"}

	folder1 := &Folder{
		children: []Inode{file1},
		name:     "Folder1",
	}

	folder2 := &Folder{
		children: []Inode{folder1, file2, file3},
		name:     "Folder2",
	}
	fmt.Println("\nPrinting hierarchy for Folder2")
	folder2.print("  ")

	cloneFolder := folder2.clone()
	fmt.Println("\nPrinting hierarchy for clone Folder")
	cloneFolder.print("  ")
}

Printing hierarchy for Folder2
  Folder2
    Folder1
        File1
    File2
    File3

Printing hierarchy for clone Folder
  Folder2_clone
    Folder1_clone
        File1_clone
    File2_clone
    File3_clone
```

### php

```php
<?php

namespace RefactoringGuru\Prototype\Conceptual;

/**
 * فئة المثال التي تمتلك قدرة الاستنساخ. سنرى كيف يتم استنساخ قيم الحقول
 * التي تحتوي على أنواع مختلفة.
 */
class Prototype
{
    public $primitive;
    public $component;
    public $circularReference;

    /**
     * توفر PHP دعمًا مدمجًا للاستنساخ. يمكنك استخدام `clone` على كائن دون
     * تعريف أي طرق خاصة طالما أن حقوله من الأنواع البدائية.
     * الحقول التي تحتوي على كائنات تحتفظ بمراجعها في الكائن المستنسخ.
     * لذلك في بعض الحالات قد ترغب في استنساخ تلك الكائنات المُشار إليها
     * أيضًا. يمكنك فعل ذلك في طريقة `__clone()` خاصة.
     */
    public function __clone()
    {
        $this->component = clone $this->component;

        // استنساخ كائن يحتوي على كائن متداخل ذي مرجع عكسي
        // يتطلب معالجة خاصة. بعد اكتمال الاستنساخ يجب أن
        // يشير الكائن المتداخل إلى الكائن المستنسخ بدلاً من الكائن الأصلي.
        $this->circularReference = clone $this->circularReference;
        $this->circularReference->prototype = $this;
    }
}

class ComponentWithBackReference
{
    public $prototype;

    /**
     * لاحظ أن المُنشئ لن يُنفَّذ أثناء الاستنساخ. إذا كان لديك
     * منطق معقد داخل المُنشئ قد تحتاج إلى تنفيذه في
     * طريقة `__clone` أيضًا.
     */
    public function __construct(Prototype $prototype)
    {
        $this->prototype = $prototype;
    }
}

/**
 * كود العميل.
 */
function clientCode()
{
    $p1 = new Prototype();
    $p1->primitive = 245;
    $p1->component = new \DateTime();
    $p1->circularReference = new ComponentWithBackReference($p1);

    $p2 = clone $p1;
    if ($p1->primitive === $p2->primitive) {
        echo "Primitive field values have been carried over to a clone. Yay!\n";
    } else {
        echo "Primitive field values have not been copied. Booo!\n";
    }
    if ($p1->component === $p2->component) {
        echo "Simple component has not been cloned. Booo!\n";
    } else {
        echo "Simple component has been cloned. Yay!\n";
    }

    if ($p1->circularReference === $p2->circularReference) {
        echo "Component with back reference has not been cloned. Booo!\n";
    } else {
        echo "Component with back reference has been cloned. Yay!\n";
    }

    if ($p1->circularReference->prototype === $p2->circularReference->prototype) {
        echo "Component with back reference is linked to original object. Booo!\n";
    } else {
        echo "Component with back reference is linked to the clone. Yay!\n";
    }
}

clientCode();

Primitive field values have been carried over to a clone. Yay!
Simple component has been cloned. Yay!
Component with back reference has been cloned. Yay!
Component with back reference is linked to the clone. Yay!

<?php

namespace RefactoringGuru\Prototype\RealWorld;

/**
 * النموذج الأولي.
 */
class Page
{
    private $title;

    private $body;

    /**
     * @var Author
     */
    private $author;

    private $comments = [];

    /**
     * @var \DateTime
     */
    private $date;

    // +100 private fields.

    public function __construct(string $title, string $body, Author $author)
    {
        $this->title = $title;
        $this->body = $body;
        $this->author = $author;
        $this->author->addToPage($this);
        $this->date = new \DateTime();
    }

    public function addComment(string $comment): void
    {
        $this->comments[] = $comment;
    }

    /**
     * يمكنك التحكم في البيانات التي تريد نقلها إلى الكائن المستنسخ.
     *
     * على سبيل المثال عند استنساخ صفحة:
     * - تحصل على عنوان جديد "Copy of ...".
     * - يبقى مؤلف الصفحة كما هو. لذا نترك المرجع
     * للكائن الموجود مع إضافة الصفحة المستنسخة إلى قائمة
     * صفحات المؤلف.
     * - لا ننقل التعليقات من الصفحة القديمة.
     * - نُرفق أيضًا كائن تاريخ جديد بالصفحة.
     */
    public function __clone()
    {
        $this->title = "Copy of " . $this->title;
        $this->author->addToPage($this);
        $this->comments = [];
        $this->date = new \DateTime();
    }
}

class Author
{
    private $name;

    /**
     * @var Page[]
     */
    private $pages = [];

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function addToPage(Page $page): void
    {
        $this->pages[] = $page;
    }
}

/**
 * كود العميل.
 */
function clientCode()
{
    $author = new Author("John Smith");
    $page = new Page("Tip of the day", "Keep calm and carry on.", $author);

    // ...

    $page->addComment("Nice tip, thanks!");

    // ...

    $draft = clone $page;
    echo "Dump of the clone. Note that the author is now referencing two objects.\n\n";
    print_r($draft);
}

clientCode();

Dump of the clone. Note that the author is now referencing two objects.

RefactoringGuru\Prototype\RealWorld\Page Object
(
    [title:RefactoringGuru\Prototype\RealWorld\Page:private] => Copy of Tip of the day
    [body:RefactoringGuru\Prototype\RealWorld\Page:private] => Keep calm and carry on.
    [author:RefactoringGuru\Prototype\RealWorld\Page:private] => RefactoringGuru\Prototype\RealWorld\Author Object
        (
            [name:RefactoringGuru\Prototype\RealWorld\Author:private] => John Smith
            [pages:RefactoringGuru\Prototype\RealWorld\Author:private] => Array
                (
                    [0] => RefactoringGuru\Prototype\RealWorld\Page Object
                        (
                            [title:RefactoringGuru\Prototype\RealWorld\Page:private] => Tip of the day
                            [body:RefactoringGuru\Prototype\RealWorld\Page:private] => Keep calm and carry on.
                            [author:RefactoringGuru\Prototype\RealWorld\Page:private] => RefactoringGuru\Prototype\RealWorld\Author Object
 *RECURSION*
                            [comments:RefactoringGuru\Prototype\RealWorld\Page:private] => Array
                                (
                                    [0] => Nice tip, thanks!
                                )

                            [date:RefactoringGuru\Prototype\RealWorld\Page:private] => DateTime Object
                                (
                                    [date] => 2018-06-04 14:50:39.306237
                                    [timezone_type] => 3
                                    [timezone] => UTC
                                )

                        )

                    [1] => RefactoringGuru\Prototype\RealWorld\Page Object
 *RECURSION*
                )

        )

    [comments:RefactoringGuru\Prototype\RealWorld\Page:private] => Array
        (
        )

    [date:RefactoringGuru\Prototype\RealWorld\Page:private] => DateTime Object
        (
            [date] => 2018-06-04 14:50:39.306272
            [timezone_type] => 3
            [timezone] => UTC
        )

)
```

### python

```python
import copy


class SelfReferencingEntity:
    def __init__(self):
        self.parent = None

    def set_parent(self, parent):
        self.parent = parent


class SomeComponent:
    """
    توفر Python واجهتها الخاصة للنموذج الأولي عبر دالتَي `copy.copy` و
    `copy.deepcopy`. وأي فئة ترغب في تنفيذ
    تطبيقات مخصصة تحتاج إلى تجاوز دالتَي العضو `__copy__` و`__deepcopy__`.
    """

    def __init__(self, some_int, some_list_of_objects, some_circular_ref):
        self.some_int = some_int
        self.some_list_of_objects = some_list_of_objects
        self.some_circular_ref = some_circular_ref

    def __copy__(self):
        """
        إنشاء نسخة سطحية. ستُستدعى هذه الطريقة كلما استدعى أحدهم
        `copy.copy` مع هذا الكائن وستُعاد القيمة المُعادة كنسخة سطحية جديدة.
        """

        # أولاً، لننشئ نسخًا من الكائنات المتداخلة.
        some_list_of_objects = copy.copy(self.some_list_of_objects)
        some_circular_ref = copy.copy(self.some_circular_ref)

        # ثم، لنستنسخ الكائن نفسه باستخدام النسخ المُعدَّة من الكائنات المتداخلة.
        new = self.__class__(
            self.some_int, some_list_of_objects, some_circular_ref
        )
        new.__dict__.update(self.__dict__)

        return new

    def __deepcopy__(self, memo=None):
        """
        إنشاء نسخة عميقة. ستُستدعى هذه الطريقة كلما استدعى أحدهم
        `copy.deepcopy` مع هذا الكائن وستُعاد القيمة المُعادة كنسخة عميقة جديدة.

        ما فائدة المعامل `memo`؟ memo هو القاموس الذي يستخدمه
        مكتبة `deepcopy` لمنع النسخ العودية اللانهائية في
        حالات المراجع الدائرية. مرّره إلى جميع استدعاءات `deepcopy`
        التي تُجريها في تنفيذ `__deepcopy__` لمنع العوديات اللانهائية.
        """
        if memo is None:
            memo = {}

        # أولاً، لننشئ نسخًا من الكائنات المتداخلة.
        some_list_of_objects = copy.deepcopy(self.some_list_of_objects, memo)
        some_circular_ref = copy.deepcopy(self.some_circular_ref, memo)

        # ثم، لنستنسخ الكائن نفسه باستخدام النسخ المُعدَّة من الكائنات المتداخلة.
        new = self.__class__(
            self.some_int, some_list_of_objects, some_circular_ref
        )
        new.__dict__ = copy.deepcopy(self.__dict__, memo)

        return new


if __name__ == "__main__":

    list_of_objects = [1, {1, 2, 3}, [1, 2, 3]]
    circular_ref = SelfReferencingEntity()
    component = SomeComponent(23, list_of_objects, circular_ref)
    circular_ref.set_parent(component)

    shallow_copied_component = copy.copy(component)

    # Let's change the list in shallow_copied_component and see if it changes in
    # component.
    shallow_copied_component.some_list_of_objects.append("another object")
    if component.some_list_of_objects[-1] == "another object":
        print(
            "Adding elements to `shallow_copied_component`'s "
            "some_list_of_objects adds it to `component`'s "
            "some_list_of_objects."
        )
    else:
        print(
            "Adding elements to `shallow_copied_component`'s "
            "some_list_of_objects doesn't add it to `component`'s "
            "some_list_of_objects."
        )

    # Let's change the set in the list of objects.
    component.some_list_of_objects[1].add(4)
    if 4 in shallow_copied_component.some_list_of_objects[1]:
        print(
            "Changing objects in the `component`'s some_list_of_objects "
            "changes that object in `shallow_copied_component`'s "
            "some_list_of_objects."
        )
    else:
        print(
            "Changing objects in the `component`'s some_list_of_objects "
            "doesn't change that object in `shallow_copied_component`'s "
            "some_list_of_objects."
        )

    deep_copied_component = copy.deepcopy(component)

    # Let's change the list in deep_copied_component and see if it changes in
    # component.
    deep_copied_component.some_list_of_objects.append("one more object")
    if component.some_list_of_objects[-1] == "one more object":
        print(
            "Adding elements to `deep_copied_component`'s "
            "some_list_of_objects adds it to `component`'s "
            "some_list_of_objects."
        )
    else:
        print(
            "Adding elements to `deep_copied_component`'s "
            "some_list_of_objects doesn't add it to `component`'s "
            "some_list_of_objects."
        )

    # Let's change the set in the list of objects.
    component.some_list_of_objects[1].add(10)
    if 10 in deep_copied_component.some_list_of_objects[1]:
        print(
            "Changing objects in the `component`'s some_list_of_objects "
            "changes that object in `deep_copied_component`'s "
            "some_list_of_objects."
        )
    else:
        print(
            "Changing objects in the `component`'s some_list_of_objects "
            "doesn't change that object in `deep_copied_component`'s "
            "some_list_of_objects."
        )

    print(
        f"id(deep_copied_component.some_circular_ref.parent): "
        f"{id(deep_copied_component.some_circular_ref.parent)}"
    )
    print(
        f"id(deep_copied_component.some_circular_ref.parent.some_circular_ref.parent): "
        f"{id(deep_copied_component.some_circular_ref.parent.some_circular_ref.parent)}"
    )
    print(
        "^^ This shows that deepcopied objects contain same reference, they "
        "are not cloned repeatedly."
    )

Adding elements to `shallow_copied_component`'s some_list_of_objects adds it to `component`'s some_list_of_objects.
Changing objects in the `component`'s some_list_of_objects changes that object in `shallow_copied_component`'s some_list_of_objects.
Adding elements to `deep_copied_component`'s some_list_of_objects doesn't add it to `component`'s some_list_of_objects.
Changing objects in the `component`'s some_list_of_objects doesn't change that object in `deep_copied_component`'s some_list_of_objects.
id(deep_copied_component.some_circular_ref.parent): 4429472784
id(deep_copied_component.some_circular_ref.parent.some_circular_ref.parent): 4429472784
^^ This shows that deepcopied objects contain same reference, they are not cloned repeatedly.
```

### ruby

```ruby
# فئة المثال التي تمتلك قدرة الاستنساخ. سنرى كيف يتم استنساخ قيم الحقول
# التي تحتوي على أنواع مختلفة.
class Prototype
  attr_accessor :primitive, :component, :circular_reference

  def initialize
    @primitive = nil
    @component = nil
    @circular_reference = nil
  end

  # @return [Prototype]
  def clone
    @component = deep_copy(@component)

    # Cloning an object that has a nested object with backreference requires
    # special treatment. After the cloning is completed, the nested object
    # should point to the cloned object, instead of the original object.
    @circular_reference = deep_copy(@circular_reference)
    @circular_reference.prototype = self
    deep_copy(self)
  end

  # deep_copy هو الحل المعتاد باستخدام Marshal لإجراء نسخ عميق. لكنه بطيء
  # وغير فعّال، لذلك في التطبيقات الحقيقية استخدم حزمة gem متخصصة.
  private def deep_copy(object)
    Marshal.load(Marshal.dump(object))
  end
end

class ComponentWithBackReference
  attr_accessor :prototype

  # @param [Prototype] prototype
  def initialize(prototype)
    @prototype = prototype
  end
end

# كود العميل.
p1 = Prototype.new
p1.primitive = 245
p1.component = Time.now
p1.circular_reference = ComponentWithBackReference.new(p1)

p2 = p1.clone

if p1.primitive == p2.primitive
  puts 'Primitive field values have been carried over to a clone. Yay!'
else
  puts 'Primitive field values have not been copied. Booo!'
end

if p1.component.equal?(p2.component)
  puts 'Simple component has not been cloned. Booo!'
else
  puts 'Simple component has been cloned. Yay!'
end

if p1.circular_reference.equal?(p2.circular_reference)
  puts 'Component with back reference has not been cloned. Booo!'
else
  puts 'Component with back reference has been cloned. Yay!'
end

if p1.circular_reference.prototype.equal?(p2.circular_reference.prototype)
  print 'Component with back reference is linked to original object. Booo!'
else
  print 'Component with back reference is linked to the clone. Yay!'
end

Primitive field values have been carried over to a clone. Yay!
Simple component has been cloned. Yay!
Component with back reference has been cloned. Yay!
Component with back reference is linked to the clone. Yay!
```

### rust

```rust
#[derive(Clone)]
struct Circle {
    pub x: u32,
    pub y: u32,
    pub radius: u32,
}

fn main() {
    let circle1 = Circle {
        x: 10,
        y: 15,
        radius: 10,
    };

    // النموذج الأولي في العمل.
    let mut circle2 = circle1.clone();
    circle2.radius = 77;

    println!("Circle 1: {}, {}, {}", circle1.x, circle1.y, circle1.radius);
    println!("Circle 2: {}, {}, {}", circle2.x, circle2.y, circle2.radius);
}

Circle 1: 10, 15, 10
Circle 2: 10, 15, 77
```

### swift

```swift
import XCTest

/// تدعم Swift الاستنساخ بشكل مدمج. لإضافة دعم الاستنساخ إلى فئتك
/// تحتاج إلى تنفيذ بروتوكول NSCopying في تلك الفئة وتوفير
/// تنفيذ لطريقة `copy`.
class BaseClass: NSCopying, Equatable {

    private var intValue = 1
    private var stringValue = "Value"

    required init(intValue: Int = 1, stringValue: String = "Value") {

        self.intValue = intValue
        self.stringValue = stringValue
    }

    /// MARK: - NSCopying
    func copy(with zone: NSZone? = nil) -> Any {
        let prototype = type(of: self).init()
        prototype.intValue = intValue
        prototype.stringValue = stringValue
        print("Values defined in BaseClass have been cloned!")
        return prototype
    }

    /// MARK: - Equatable
    static func == (lhs: BaseClass, rhs: BaseClass) -> Bool {
        return lhs.intValue == rhs.intValue && lhs.stringValue == rhs.stringValue
    }
}

/// يمكن للفئات الفرعية تجاوز طريقة `copy` الأساسية لنسخ بياناتها الخاصة إلى
/// الكائن الناتج. لكن يجب عليك دائمًا استدعاء الطريقة الأساسية أولاً.
class SubClass: BaseClass {

    private var boolValue = true

    func copy() -> Any {
        return copy(with: nil)
    }

    override func copy(with zone: NSZone?) -> Any {
        guard let prototype = super.copy(with: zone) as? SubClass else {
            return SubClass() // oops
        }
        prototype.boolValue = boolValue
        print("Values defined in SubClass have been cloned!")
        return prototype
    }
}

/// كود العميل.
class Client {
    // ...
    static func someClientCode() {
        let original = SubClass(intValue: 2, stringValue: "Value2")

        guard let copy = original.copy() as? SubClass else {
            XCTAssert(false)
            return
        }

        /// انظر تنفيذ بروتوكول `Equatable` لمزيد من التفاصيل.
        XCTAssert(copy == original)

        print("The original object is equal to the copied object!")
    }
    // ...
}

/// لنرى كيف تعمل الأجزاء معًا.
class PrototypeConceptual: XCTestCase {

    func testPrototype_NSCopying() {
        Client.someClientCode()
    }
}

Values defined in BaseClass have been cloned!
Values defined in SubClass have been cloned!
The original object is equal to the copied object!

import XCTest

class PrototypeRealWorld: XCTestCase {

    func testPrototypeRealWorld() {

        let author = Author(id: 10, username: "Ivan_83")
        let page = Page(title: "My First Page", contents: "Hello world!", author: author)

        page.add(comment: Comment(message: "Keep it up!"))

        /// بما أن NSCopying تُعيد Any، يجب فك التغليف عن الكائن المنسوخ.
        guard let anotherPage = page.copy() as? Page else {
            XCTFail("Page was not copied")
            return
        }

        /// يجب أن تكون التعليقات فارغة لأنها صفحة جديدة.
        XCTAssert(anotherPage.comments.isEmpty)

        /// لاحظ أن المؤلف يشير الآن إلى كائنين.
        XCTAssert(author.pagesCount == 2)

        print("Original title: " + page.title)
        print("Copied title: " + anotherPage.title)
        print("Count of pages: " + String(author.pagesCount))
    }
}

private class Author {

    private var id: Int
    private var username: String
    private var pages = [Page]()

    init(id: Int, username: String) {
        self.id = id
        self.username = username
    }

    func add(page: Page) {
        pages.append(page)
    }

    var pagesCount: Int {
        return pages.count
    }
}

private class Page: NSCopying {

    private(set) var title: String
    private(set) var contents: String
    private weak var author: Author?
    private(set) var comments = [Comment]()

    init(title: String, contents: String, author: Author?) {
        self.title = title
        self.contents = contents
        self.author = author
        author?.add(page: self)
    }

    func add(comment: Comment) {
        comments.append(comment)
    }

    /// MARK: - NSCopying

    func copy(with zone: NSZone? = nil) -> Any {
        return Page(title: "Copy of '" + title + "'", contents: contents, author: author)
    }
}

private struct Comment {

    let date = Date()
    let message: String
}

Original title: My First Page
Copied title: Copy of 'My First Page'
Count of pages: 2
```

### typescript

```typescript
/**
 * فئة المثال التي تمتلك قدرة الاستنساخ. سنرى كيف يتم استنساخ قيم الحقول
 * التي تحتوي على أنواع مختلفة.
 */
class Prototype {
    public primitive: any;
    public component: object;
    public circularReference: ComponentWithBackReference;

    public clone(): this {
        const clone = Object.create(this);

        clone.component = Object.create(this.component);

        // استنساخ كائن يحتوي على كائن متداخل ذي مرجع عكسي
        // يتطلب معالجة خاصة. بعد اكتمال الاستنساخ يجب أن
        // يشير الكائن المتداخل إلى الكائن المستنسخ بدلاً من الكائن الأصلي.
        // يمكن أن يكون عامل الانتشار (spread) مفيدًا في هذه الحالة.
        clone.circularReference = new ComponentWithBackReference(clone);

        return clone;
    }
}

class ComponentWithBackReference {
    public prototype;

    constructor(prototype: Prototype) {
        this.prototype = prototype;
    }
}

/**
 * كود العميل.
 */
function clientCode() {
    const p1 = new Prototype();
    p1.primitive = 245;
    p1.component = new Date();
    p1.circularReference = new ComponentWithBackReference(p1);

    const p2 = p1.clone();
    if (p1.primitive === p2.primitive) {
        console.log('Primitive field values have been carried over to a clone. Yay!');
    } else {
        console.log('Primitive field values have not been copied. Booo!');
    }
    if (p1.component === p2.component) {
        console.log('Simple component has not been cloned. Booo!');
    } else {
        console.log('Simple component has been cloned. Yay!');
    }

    if (p1.circularReference === p2.circularReference) {
        console.log('Component with back reference has not been cloned. Booo!');
    } else {
        console.log('Component with back reference has been cloned. Yay!');
    }

    if (p1.circularReference.prototype === p2.circularReference.prototype) {
        console.log('Component with back reference is linked to original object. Booo!');
    } else {
        console.log('Component with back reference is linked to the clone. Yay!');
    }
}

clientCode();

Primitive field values have been carried over to a clone. Yay!
Simple component has been cloned. Yay!
Component with back reference has been cloned. Yay!
Component with back reference is linked to the clone. Yay!
```

