Նախատիպ (նախագծման ձևանմուշ)

Նախատիպը նախագծման ստեղծող ձևանմուշ է, որը նոր օբյեկտներ է ստեղծում նախօրոք սահմված նախատիպը պատճենելով։

Ընդհանուր հասկացողություններ 
 Client - հայցող
 Instance - նմուշ
 Implementation - իրականացում
 Product - արգասիք

Նկարագրություն 
Նախատիպ ձևանմուշն օգտագործվում է հետևյալ նպատակների համար.
 խուսափում է ենթադասերի ստեղծող օբյեկտների ժառանգումից հայցողի ծրագրային ապահովման մեջ, ինչպես այդ անում է Աբստրակտ ֆաբրիկա ձևանմուշը։
 խուսափում է ստանդարտ ճանապարհով օբյեկտի ստեղծման վրա լրացուցիչ ջանքերից (ի նկատի ունի կոսնտրուկտորի օգտագործումը, քանի որ այս դեպքում նույնպես կկանչվեն կոնստրուկտորներ ողջ հիերարխիայի համար), երբ նրա ծախսած ժամանակը անթույլատրելի թանկ է ծրագրային ապահովվության համար։

Նախագծման այս ձևանմուշը խորհուրդ է տրվում օգտագործել, երբ համակարգը չպետք է կախված լինի նրանից, թե ինչպես են նրանում ստեղծվում, կոմպանավորվում և ներկայացվում արգասիքները.
 ինտանսավորված դասերը բնորոշվում են իրականցման ժամանակ (օրինակ դինամիկ բեռնման օգնությամբ).
 զուգահեռ հիերարխիա ունեցող արգասիքներում դասերի հիերարխիայի կառուցումից կամ ֆաբրիկաներից խուսափելու համար,
 դասերի նմուշները կարող են գտնվել տարբեր վիճակներում։ Կարող է ավելի նպատակահարմար լինի ունենալ համապատասխան թվով նախատիպեր և կլոնավորել դրանք, քան թե դասից ամեն անգամ անհրաժեշտ վիճակով նմուշ ստեղծել։

Կառուցվածք

Պսեվդոկոդ 
 class WordOccurrences is
  field occurrences is
   The list of the index of each occurrence of the word in the text.
 
  constructor WordOccurrences(text, word) is
    input։ the text in which the occurrences have to be found
    input։ the word that should appear in the text
   Empty the occurrences list
   for each textIndex in text
    isMatching ։= true
    for each wordIndex in word
     if the current word character does not match the current text character then
      isMatching ։= false
    if isMatching is true then
     Add the current textIndex into the occurrences list
 
  method getOneOccurrenceIndex(n) is
    input։ a number to point on the nth occurrence.
    output։ the index of the nth occurrence.
   Return the nth item of the occurrences field if any.
 
  method clone() is
    output։ a WordOccurrences object containing the same data.
   Call clone() on the super class.
   On the returned object, set the occurrences field with the value of the local occurrences field.
   Return the cloned object.
 
 text ։= "The prototype pattern is a creational design pattern in software development first described in design patterns, the book."
 word ։= "pattern"d
 searchEngine := new WordOccurrences(text, word)
 anotherSearchEngine := searchEngine.clone()

(այս ալգորիթմը օպտիմիզացիայի ենթարկված չէ)

Օրինակներ

C++ 
class Meal {
public:
	virtual ~Meal();
	virtual void eat() = 0;
	virtual Meal *clone() const = 0;
	//...
};
class Spaghetti : public Meal {
public:
	Spaghetti( const Spaghetti &);
	void eat();
	Spaghetti *clone() const { return new Spaghetti( *this ); }
	//...
};

Java 
/**
 * Prototype Class
 */
public class Cookie implements Cloneable {
    
    protected int weight;

    @Override
    public Cookie clone() throws CloneNotSupportedException {
        Cookie copy = new Cookie();
        copy.weight = this.weight;
       
        //In an actual implementation of this pattern you might now change references to
        //the expensive to produce parts from the copies that are held inside the prototype.

        return copy;
    }
}

/**
 * Concrete Prototypes to clone
 */
public class CoconutCookie extends Cookie { }
/**
 * Client Class
 */
public class CookieMachine {

    private Cookie cookie; // Could have been a private Cloneable cookie.

    public CookieMachine(Cookie cookie) {
        this.cookie = cookie;
    }

    public Cookie makeCookie() throws CloneNotSupportedException {
        return (Cookie) this.cookie.clone();
    }

    public static void main(String args[]) throws CloneNotSupportedException {
        Cookie tempCookie = null;
        Cookie prot = new CoconutCookie();
        CookieMachine cm = new CookieMachine(prot);
        for (int i = 0; i < 100; i++)
            tempCookie = cm.makeCookie();
    }
}

C# 
 using System;
 
 namespace Prototype
 {  
  class MainApp
  {    
    static void Main()
    {
      // Create two instances and clone each
 
      Prototype p1 = new ConcretePrototype1("I");
      Prototype c1 = p1.Clone();
      Console.WriteLine ("Cloned: {0}", c1.Id);
 
      Prototype p2 = new ConcretePrototype2("II");
      Prototype c2 = p2.Clone();
      Console.WriteLine ("Cloned: {0}", c2.Id);
 
      // Wait for user
      Console.Read();
    }
  }
 
  // "Prototype"
 
  abstract class Prototype
  {
    private string id;
 
    // Constructor
    public Prototype(string id)
    {
      this.id = id;
    }
 
    // Property
    public string Id
    {
      get{ return id; }
    }
 
    public abstract Prototype Clone();
  }
 
  // "ConcretePrototype1"
 
  class ConcretePrototype1 : Prototype
  {
    // Constructor
    public ConcretePrototype1(string id) : base(id)
    {
    }
 
    public override Prototype Clone()
    {
      // Shallow copy
      return (Prototype)this.MemberwiseClone();
    }
  }
 
  // "ConcretePrototype2"
 
  class ConcretePrototype2 : Prototype
  {
    // Constructor
    public ConcretePrototype2(string id) : base(id)
    {
    }
 
    public override Prototype Clone()
    {
      // Shallow copy
      return (Prototype)this.MemberwiseClone();
    }
  }
 }

PHP 
<p style="text-align:left">
<?php
/**
 * Հասանելի դասերի հիերարխիա նախատիպերի ստեղծման համար
 */ 
abstract class Terrain {}

abstract class Sea extends Terrain {}
class EarthSea extends Sea {}
class MarsSea extends Sea {}
class VenusSea extends Sea {}

abstract class Plains extends Terrain {}
class EarthPlains extends Plains {}
class MarsPlains extends Plains {}
class VenusPlains extends Plains {}

abstract class Forest extends Terrain {}
class EarthForest extends Forest {}
class MarsForest extends Forest {}
class VenusForest extends Forest {}

/**
 * Նախատիպի ֆաբրիկայի տրամաբանության որոշում
 */
class TerrainFactory {
    private $sea;
    private $forest;
    private $plains;

    public function __construct( Sea $sea, Plains $plains, Forest $forest ) {
        $this->sea = $sea;
        $this->plains = $plains;
        $this->forest = $forest;
    }
    function getSea( ) {
        return clone $this->sea;
    }
    function getPlains( ) {
        return clone $this->plains;
    }
    function getForest( ) {
        return clone $this->forest;
    }
}

/**
 * Ֆաբրիկայի ստեղծումը ըստ նախատիպի տրված պարամետրերի
 */
$prototypeFactory = new TerrainFactory(
new EarthSea(),
new MarsPlains(),
new VenusForest()
);

/**
 * Տրված օբյեկտների ստեղծումը կլոնավորման միջոցով
 */
$sea = $prototypeFactory->getSea();
$plains = $prototypeFactory->getPlains();
$forest = $prototypeFactory->getForest();

Ruby 
module Prototype

  # "Prototype"
 
  class Prototype
  
    # Property
    # id-ի հատկությունը սկզբում առկա է ամեն օբյեկտի մոտ, դրա համար էլ օգտագործվում է name հատկությունը

    attr_reader :name

    # Constructor

    def initialize name
      @name = name
    end
 
  end
end
 
# Create an instance and clone it
p1 = Prototype::Prototype.new "my name" # Prototype դասի օբյեկտը ստեղծվում է ավանդական ճանապարհով` new մեթոդով
p2 = p1.clone # clone մեթոդը ի սկզբանե գոյություն ունի բոլոր օբյետկների համար։ Նրան բնորոշել պետք չէ

puts "p1.id = #{p1.id}, p2.id = #{p2.id}" # կտպվեն տարբեր id-ներ
puts "p1.name = #{p1.name}, p2.name = #{p2.name}" # կտպվի միևնույն name-ը- "my name"

# Wait for user
gets

VB.NET 
Namespace Prototype
    Class MainApp
        Shared Sub Main()
            ' Երկու նախատիպերի ստեղծում և նրանցից յուրաքանչյուրի կլոնավորում

            Dim p1 As Prototype = New ConcretePrototype1("I")
            Dim c1 As Prototype = p1.Clone()
            Console.WriteLine("Cloned: {0}", c1.Id)

            Dim p2 As Prototype = New ConcretePrototype2("II")
            Dim c2 As Prototype = p2.Clone()
            Console.WriteLine("Cloned: {0}", c2.Id)

            Console.Read()
        End Sub
    End Class

    ' "Prototype"

    MustInherit Class Prototype
        Private m_id As String

        ' Կոնստրուկտոր
        Public Sub New(ByVal id As String)
            Me.m_id = id
        End Sub

        ' Հատկություն
        Public ReadOnly Property Id() As String
            Get
                Return m_id
            End Get
        End Property

        Public MustOverride Function Clone() As Prototype
    End Class

    ' "ConcretePrototype1"

    Class ConcretePrototype1

        Inherits Prototype
        ' Конструктор
        Public Sub New(ByVal id As String)
            MyBase.New(id)
        End Sub

        Public Overrides Function Clone() As Prototype
            ' Неполная копия
            Return DirectCast(Me.MemberwiseClone(), Prototype)
        End Function
    End Class

    ' "ConcretePrototype2"

    Class ConcretePrototype2
        Inherits Prototype

        ' Конструктор
        Public Sub New(ByVal id As String)
            MyBase.New(id)
        End Sub

        Public Overrides Function Clone() As Prototype
            ' Неполная копия
            Return DirectCast(Me.MemberwiseClone(), Prototype)
        End Function
    End Class
End Namespace

Delphi 
program PrototypePattern;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TPrototype = class
  public
    function Clone: TPrototype; virtual; abstract;
  end;

type
  TPrototypeType = class(TPrototype)
  private
    FID: Integer;
    FInfo: String;
  public
    property ID: Integer read FID write FID;
    property Info: String read FInfo write FInfo;

    function Clone: TPrototype; override;
  end;

  function TPrototypeType.Clone: TPrototype;
  var
    vClone: TPrototypeType;
  begin
    vClone := TPrototypeType.Create;
    vClone.ID := ID;
    vClone.Info := Info;

    Result := vClone;
  end;

procedure CloneAndShow(Prototype: TPrototypeType);
var
  vClone: TPrototypeType;
begin
  vClone := Prototype.Clone;
  try
    Write(vClone.ID);
    Write(vClone.Info);
  finally
    vClone.Free;
  end;

  WriteLn;
end;

var
  vConcretePrototype1, vConcretePrototype2: TPrototypeType;
begin
  vConcretePrototype1 := TPrototypeType.Create;
  vConcretePrototype2 := TPrototypeType.Create;
  try
    vConcretePrototype1.ID := 10;
    vConcretePrototype1.Info := ' Prototype1!';

    vConcretePrototype2.ID := 11;
    vConcretePrototype2.Info := ' Prototype2!';

    CloneAndShow(vConcretePrototype1);
    CloneAndShow(vConcretePrototype2);
  finally
    vConcretePrototype1.Free;
    vConcretePrototype2.Free;
  end;

  ReadLn;
end.

CoffeeScript 
class PresidentPrototype
  constructor: (@proto) ->
  clone: ->
    customer = new President()
    customer.first = @proto.first
    customer.last = @proto.last
    customer.aka = @proto.aka
    customer

class President
  constructor: (@first, @last, @aka) ->
  say: -> console.log "His name is #{@first} #{@last} aka #{@aka}."

run = ->
  proto = new President("Jimmy", "Wales", "Jimbo")
  prototype = new PresidentPrototype(proto)
  customer = prototype.clone()
  customer.say()

run()

Ծանոթագրություններ 

Ծրագրավորում