اشتراک‌ها
jQuery 3.5.0 منتشر شد

The main change in this release is a security fix, and it’s possible you will need to change your own code to adapt. Here’s why: jQuery used a regex in its jQuery.htmlPrefilter method to ensure that all closing tags were XHTML-compliant when passed to methods. For example, this prefilter ensured that a call like jQuery("<div class='hot' />") is actually converted to jQuery("<div class='hot'></div>"). Recently, an issue was reported that demonstrated the regex could introduce a cross-site scripting (XSS) vulnerability. 

jQuery 3.5.0 منتشر شد
اشتراک‌ها
Bootstrap 4.5.0 منتشر شد
  • New interaction utilities. Quickly set user-select with the new utilities and Sass map.
  • New Reboot style for pointer cursors. We now include a role="button" selector in Reboot to set cursor: pointer on non-<button> element buttons.
  • Examples are now downloadable. We’ve added a script to zip up and offer all our Examples as their own download from the docs.
  • Saved ~5% from the compressed minified JS builds. 
Bootstrap 4.5.0 منتشر شد
مطالب
Design Pattern: Factory

الگوهای طراحی، سندها و راه حلهای از پیش تعریف شده و تست شده‌ای برای مسائل و مشکلات روزمره‌ی برنامه نویسی می‌باشند که هر روزه ما را درگیر خودشان می‌کنند. هر چقدر مقیاس پروژه وسیعتر و تعداد کلاسها و اشیاء بزرگتر باشند، درگیری برنامه نویس و چالش برای مرتب سازی و خوانایی برنامه و همچنین بالا بردن کارآیی و امنیت افزون‌تر می‌شود. از همین رو استفاده از ساختارهایی تست شده برای سناریوهای یکسان، امری واجب تلقی می‌شود.

الگوهای طراحی از لحاظ سناریو، به سه گروه عمده تقسیم می‌شوند:

1- تکوینی: هر چقدر تعداد کلاسها در یک پروژه زیاد شود، به مراتب تعداد اشیاء ساخته شده از آن نیز افزوده شده و پیچیدگی و درگیری نیز افزایش می‌یابد. راه حل‌هایی از این دست، تمرکز بر روی مرکزیت دادن به کلاسها با استفاده از رابط‌ها و کپسوله نمودن (پنهان سازی) اشیاء دارد. 

2- ساختاری: گاهی در پروژه‌ها پیش می‌آید که می‌خواهیم ارتباط بین دو کلاس را تغییر دهیم. از این رو امکان از هم پاشی اجزایِ دیگر پروژه پیش می‌آید. راه حلهای ساختاری، سعی در حفظ انسجام پروژه در برابر این دست از تغییرات را دارند.

3- رفتاری: گاهی بنا به مصلحت و نیاز مشتری، رفتار یک کلاس می‌بایستی تغییر نماید. مثلا چنانچه کلاسی برای ارائه صورتحساب داریم و در آن میزان مالیات 30% لحاظ شده است، حال این درصد باید به عددی دیگر تغییر کند و یا پایگاه داده به جای مشاهده‌ی تعدادِ معدودی گره از درخت، حال می‌بایست تمام گره‌ها را ارائه نماید.


الگوی فکتوری:

الگوی فکتوری در دستهء اول قرار می‌گیرد. من در اینجا به نمونه‌ای از مشکلاتی که این الگو حل می‌نماید، اشاره می‌کنم:

فرض کنید یک شرکت بزرگ قصد دارد تا جزییات کامل خرید هر مشتری را با زدن دکمه چاپ ارسال نماید. چنین شرکت بزرگی بر اساس سیاستهای داخلی، بر حسب میزان خرید، مشتریان را به چند گروه مشتری معمولی و مشتری ممتاز تقسیم می‌نماید. در نتیجه نمایش جزییات برای آنها با احتساب میزان تخفیف و به عنوان مثال تعداد فیلدهایی که برای آنها در نظر گرفته شده است، تفاوت دارد. بنابراین برای هر نوع مشتری یک کلاس وجود دارد.


یک راه این است که با کلیک روی دکمه‌ی چاپ، نوع مشتری تشخیص داده شود و به ازای نوع مشتری، یک شیء از کلاس مشخص شده برای همان نوع ساخته شود.

 

 

            // Get Customer Type from Customer click on Print Button
            int customerType = 0;

            // Create Object without instantiation
            object obj;


            //Instantiate obj according to customer Type
            if (customerType == 1)
            {
                obj = new Customer1();
            }
            else if (customerType == 2)
            {
                obj = new Customer2();
            }
            // Problem:
            //          1: Scattered New Keywords
            //          2: Client side is aware of Customer Type

 همانگونه که مشاهده می‌نمایید در این سبک کدنویسی غیرحرفه‌ای، مشکلاتی مشهود است که قابل اغماض نیستند. در ابتدا سمت کلاینت دسترسی مستقیم به کلاسها دارد و همانگونه که در شکل بالا قابل مشاهده است کلاینت مستقیما به کلاس وصل است. مشکل دوم عدم پنهان سازی کلاس از دید مشتری است.

راه حل: این مشکل با استفاده از الگوی فکتوری قابل حل است. با استناد به الگوی فکتوری، کلاینت تنها به کلاس فکتوری و یک اینترفیس دسترسی دارد و کلاسهای فکتوری و اینترفیس، حق دسترسی به کلاسهای اصلی برنامه را دارند.

گام نخست: در ابتدا یک class library  به نام Interface ساخته و در آن یک کلاس با نام ICustomer  می سازیم   که متد Report() را معرفی می‌نماید.

  //Interface

namespace Interface
{
    public interface ICustomer
    {
        void Report();
    }
}

گام دوم: یک class library  به نام MainClass  ساخته و با Add Reference کلاس Interface را اضافه نموده، در آن دو کلاس با نام Customer1, Customer2 می‌سازیم و using Interface را Import می‌نماییم. هر دو کلاس از ICustomer  ارث می‌برند و  سپس متد Report() را در هر دو کلاس Implement می‌نماییم.

// Customer1
using System;
using Interface;

namespace MainClass
{
    public class Customer1 : ICustomer
    {
        public void Report()
        {           
            Console.WriteLine("این گزارش مخصوص مشتری نوع اول است");           
        }
    }
}

//Customer2
using System;
using Interface;

namespace MainClass
{
   public class Customer2 : ICustomer
    {
        public void Report()
        {           
            Console.WriteLine("این گزارش مخصوص مشتری نوع دوم است");           
        }
    }
}

گام سوم: یک class library  به نام FactoryClass  ساخته و با Add Reference کلاس Interface, MainClass را اضافه نموده، در آن یک کلاس با نام clsFactory  می سازیم و using Interface, using MainClass را Import می‌نماییم. پس از آن یک متد با نام getCustomerType ساخته که ورودی آن نوع مشتری از نوع int است و خروجی آن از نوع Interface-ICustomer و بر اساس کد نوع مشتری object را از کلاس Customer1 و یا Customer2 می‌سازیم و آن را return می نماییم.

//Factory
using System;
using Interface;
using MainClass;

namespace FactoryClass
{
    public class clsFactory
    {
        static public ICustomer getCustomerType(int intCustomerType)
        {
            ICustomer objCust;
            if (intCustomerType == 1)
            {
                objCust = new Customer1();
            }
            else if (intCustomerType == 2)
            {
                objCust = new Customer2();
            }
            else
            {
                return null;
            }
            return objCust;
        }
    }
}

گام چهارم (آخر): در قسمت UI   Client، کد نوع مشتری را از کاربر دریافت کرده و با Add Reference کلاس Interface, FactoryClass را اضافه نموده (دقت نمایید هیچ دسترسی به کلاس‌های اصلی وجود ندارد)، و using Interface,  using FactoryClass را Import می‌نماییم. از clsFactory تابع  getCustomerType را فراخوانی نموده (به آن کد نوع مشتری را پاس می‌دهیم) و خروجی آن را که از نوع اینترفیس است به یک object از نوع ICustomer  نسبت می‌دهیم. سپس از این object  متد Report را فراخوانی می‌نماییم. همانطور که از شکل و کدها مشخص است، هیچ رابطه ای بین UI(Client) و کلاسهای اصلی برقرار نیست.

//UI (Client)
using System;
using FactoryClass;
using Interface;

namespace DesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            int intCustomerType = 0;
            ICustomer objCust;
            Console.WriteLine("نوع مشتری را وارد نمایید");           
            intCustomerType = Convert.ToInt16(Console.ReadLine());
            objCust = clsFactory.getCustomerType(intCustomerType);
            objCust.Report();
            Console.ReadLine();
        }
    }
}

مطالب
تزریق وابستگی (dependency injection) به زبان ساده

این مطلب در ادامه‌ی "آشنایی با الگوی IOC یا Inversion of Control (واگذاری مسئولیت)" می‌باشد که هر از چندگاهی یک قسمت جدید و یا کاملتر از آن ارائه خواهد شد.

==============
به صورت خلاصه ترزیق وابستگی و یا dependency injection ، الگویی است جهت تزریق وابستگی‌های خارجی یک کلاس به آن، بجای استفاده مستقیم از آن‌ها در درون کلاس.
برای مثال شخصی را در نظر بگیرید که قصد خرید دارد. این شخص می‌تواند به سادگی با کمک یک خودرو خود را به اولین محل خرید مورد نظر برساند. حال تصور کنید که 7 نفر عضو یک گروه، با هم قصد خرید دارند. خوشبختانه چون تمام خودروها یک اینترفیس مشخصی داشته و کار کردن با آن‌ها تقریبا شبیه به یکدیگر است، حتی اگر از یک ون هم جهت رسیدن به مقصد استفاده شود، امکان استفاده و راندن آن همانند سایر خودروها می‌باشد و این دقیقا همان مطلبی است که هدف غایی الگوی تزریق وابستگی‌ها است. بجای این‌که همیشه محدود به یک خودرو برای استفاده باشیم، بنابر شرایط، خودروی متناسبی را نیز می‌توان مورد استفاده قرار داد.
در دنیای نرم افزار، وابستگی کلاس Driver ، کلاس Car است. اگر موارد ذکر شده را بدون استفاده از تزریق وابستگی‌ها پیاده سازی کنیم به کلاس‌های زیر خواهیم رسید:

//Person.cs
namespace DependencyInjectionForDummies
{
class Person
{
public string Name { get; set; }
}
}

//Car.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Car
{
List<Person> _passengers = new List<Person>();

public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}

public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}

//Driver.cs
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Driver
{
private Car _myCar = new Car();

public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);

_myCar.Drive();
}
}
}

//Program.cs
using System.Collections.Generic;
using System;

namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
new Driver().DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});

Console.WriteLine("Press a key ...");
Console.ReadKey();
}
}
}

توضیحات:
کلاس شخص (Person) جهت تعریف مسافرین، اضافه شده؛ سپس کلاس خودرو (Car) که اشخاص را می‌توان به آن اضافه کرده و سپس به مقصد رساند، تعریف گردیده است. همچنین کلاس راننده (Driver) که بر اساس لیست مسافرین، آن‌ها را به خودروی خاص ذکر شده هدایت کرده و سپس آن‌ها را با کمک کلاس خودرو به مقصد می‌رساند؛ نیز تعریف شده است. در پایان هم یک کلاینت ساده جهت استفاده از این کلاس‌ها ذکر شده است.
همانطور که ملاحظه می‌کنید کلاس راننده به کلاس خودرو گره خورده است و این راننده همیشه تنها از یک نوع خودروی مشخص می‌تواند استفاده کند و اگر روزی قرار شد از یک ون کمک گرفته شود، این کلاس باید بازنویسی شود.

خوب! اکنون اگر این کلاس‌ها را بر اساس الگوی تزریق وابستگی‌ها (روش تزریق در سازنده که در قسمت قبل بحث شد) بازنویسی کنیم به کلاس‌های زیر خواهیم رسید:

//ICar.cs
using System;

namespace DependencyInjectionForDummies
{
interface ICar
{
void AddPassenger(Person p);
void Drive();
}
}

//Car.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Car : ICar
{
//همانند قسمت قبل
}
}

//Van.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Van : ICar
{
List<Person> _passengers = new List<Person>();

public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}

public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}

//Driver.cs
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Driver
{
private ICar _myCar;

public Driver(ICar myCar)
{
_myCar = myCar;
}

public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);

_myCar.Drive();
}
}
}

//Program.cs
using System.Collections.Generic;
using System;

namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
Driver driver = new Driver(new Van());
driver.DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});

Console.WriteLine("Press a key ...");
Console.ReadKey();
}
}
}

توضیحات:
در اینجا یک اینترفیس جدید به نام ICar اضافه شده است و بر اساس آن می‌توان خودروهای مختلفی را با نحوه‌ی بکارگیری یکسان اما با جزئیات پیاده سازی متفاوت تعریف کرد. برای مثال در ادامه، یک کلاس ون با پیاده سازی این اینترفیس تشکیل شده است. سپس کلاس راننده‌ی ما بر اساس ترزیق این اینترفیس در سازنده‌ی آن بازنویسی شده است. اکنون این کلاس دیگر نمی‌داند که دقیقا چه خودرویی را باید مورد استفاده قرار دهد و از وابستگی مستقیم به نوعی خاص از آن‌ها رها شده است؛ اما می‌داند که تمام خودروها، اینترفیس مشخص و یکسانی دارند. به تمام آن‌ها می‌توان مسافرانی را افزود و سپس به مقصد رساند. در پایان نیز یک راننده جدید بر اساس خودروی ون تعریف شده، سپس یک سری مسافر نیز تعریف گردیده و نهایتا متد DriveToMarket فراخوانی شده است.
به این صورت به یک سری کلاس اصطلاحا loosely coupled رسیده‌ایم. دیگر راننده‌ی ما وابسته‌ی به یک خودروی خاص نیست و هر زمانی که لازم بود می‌توان خودروی مورد استفاده‌ی او را تغییر داد بدون اینکه کلاس راننده را بازنویسی کنیم.
یکی دیگر از مزایای تزریق وابستگی‌ها ساده سازی unit testing کلاس‌های برنامه توسط mocking frameworks است. به این صورت توسط این نوع فریم‌ورک‌ها می‌توان رفتار یک خودرو را تقلید کرد بجای اینکه واقعا با تمام ریز جرئیات آن‌ها بخواهیم سروکار داشته باشیم (وابستگی‌ها را به صورت مستقل می‌توان آزمایش کرد).

مطالب
پیاده سازی الگوی طراحی Memento

Memento یک الگوی طراحی مفید و ساده است که برای ذخیره و بازیابی state یک object استفاده می‌شود. در بعضی از مقالات از آن به عنوان snapshot نیز یاد شده است! اگر با git  کار کرده باشید، این مفهوم را می‌توان در git بسیار یافت؛ هر commit به عنوان یک snapshot میباشد که میتوان به صورت مکرر آن را undo کرد و یا مثال خیلی ساده‌تر میتوان به ctrl+z در سیستم عامل اشاره کرد.

به مثال زیر توجه کنید:

Int temp;
Int a=1;
temp=a;
a=2;
.
.
a=temp;

شما قطعا در برنامه نویسی با کد بالا زیاد برخورد داشته‌اید و آن‌را به صورت مکرر انجام داده‌اید. کد بالا را در قالب یک object بیان میکنیم. به مثال زیر توجه کنید:

int main()
{
  MyClass One = new MyClass();
  MyClass Temp = new MyClass();
  // Set an initial value.
  One.Value = 10;
  One.Name = "Ten";
  // Save the state of the value.
  Temp.Value = One.Value;
  Temp.Name = One.Name;
  // Change the value.
  One.Value = 99;
  One.Name = "Ninety Nine";
  // Undo and restore the state.
  One.Value = Temp.Value;
  One.Name = Temp.Name;
}

در کد بالا با استفاده از یک temp، شیء مورد نظر را ذخیره کرده و در آخر مجدد داده‌ها را درون شیء، restore  میکنیم.


 از مشکلات کد بالا میتوان گفت :

۱- برای هر object باید یک شیء temp ایجاد کنیم.

۲- ممکن است بخواهیم که حالات یک object را بر روی هارد ذخیره کنیم. با روش فوق کدها خیلی پیچیده‌تر خواهند شد.

۳- نوشتن کد به این سبک برای پروژه‌های بزرگ، پیچیده و مدیریت آن سخت‌تر می‌شود.


پیاده سازی memento

ما این مثال را در قالب یک پروژه NET Core  onsole. ایجاد میکنیم. برای این کار یک پوشه‌ی جدید را ایجاد و درون ترمینال دستور زیر را وارد کنید:

dotnet new console

روش‌های زیادی برای پیاده سازی memento وجود دارند. برای پیاده سازی memento ابتدا یک abstract class را به شکل زیر ایجاد میکنیم: 

abstract class MementoBase
{
  protected Guid mementoKey = Guid.NewGuid();
  abstract public void SaveMemento(Memento memento);
  abstract public void RestoreMemento(Memento memento);
}

اگر به کلاس بالا دقت کنید، این کلاس قرار است parent کلاس‌های دیگری باشد که داری دو متد SaveMemento و RestoreMemento برای ذخیره و بازیابی و همچنین یک Guid برای نگهداری state‌های مختلف میباشد.

ورودی متدها از نوع memento میباشد. پس کلاس memento را به شکل زیر ایجاد می‌کنیم:

class Memento
{
    private Dictionary<Guid, object> stateList = new Dictionary<Guid, object>();
    public object GetState(Guid key)
    {
        return stateList[key];
    }
    public void SetState(Guid key, object newState)
    {
        stateList[key] = newState;
    }
    public Memento()
    {
    }
}

در کد بالا با یک Dictionary می‌توان هر object را با کلیدش ذخیره کنیم. توجه کنید که value دیکشنری از نوع object میباشد و چون object پدر تمام object‌های دیگر است پس می‌توانیم هر نوع داده‌ای را در آن ذخیره کنیم. تا اینجا، Memento پیاده سازی شده است. میتوان این کار را با جنریک‌ها نیز پیاده سازی کرد.

در ادامه می‌خواهیم یک کلاس بسازیم و حالت‌های مختلف را در آن بررسی کنیم. کلاس زیر را ایجاد کنید:

class ConcreteOriginator : MementoBase
{
  private int value = 0;
  public ConcreteOriginator(int newValue)
  {
    SetData(newValue);
  }
  public void SetData(int newValue)
  {
    value = newValue;
  }
  public void Speak()
  {
    Console.WriteLine("My value is " + value.ToString());
  }
  public override void SaveMemento(Memento memento)
  {
    memento.SetState(mementoKey, value);
  }
  public override void RestoreMemento(Memento memento)
  {
    int restoredValue = (int)memento.GetState(mementoKey);
    SetData(restoredValue);
  }
}

کلاس ConcreteOriginator از کلاس MementoBase ارث بری کرده و دو متد RestoreMemento و SaveMemento را پیاده سازی میکند و همچنین دارای یک مشخصه value می‌باشد. برای خروجی گرفتن، متد main را به صورت زیر پیاده سازی می‌کنیم:

static void Main(string[] args)
{
  Memento memento = new Memento();
  // Create an originator, which will hold our state data.
  ConcreteOriginator myOriginator = new ConcreteOriginator("Hello World!", StateType.ONE);
  ConcreteOriginator anotherOriginator = new ConcreteOriginator("Hola!", StateType.ONE);
  ConcreteOriginator2 thirdOriginator = new ConcreteOriginator2(7);
  // Set some state data.
  myOriginator.Speak();
  anotherOriginator.Speak();
  thirdOriginator.Speak();
  // Save the states into our memento.
  myOriginator.SaveMemento(memento);
  anotherOriginator.SaveMemento(memento);
  thirdOriginator.SaveMemento(memento);
  // Now change our originators' states.
  myOriginator.SetData("Goodbye!", StateType.TWO);
  anotherOriginator.SetData("Adios!", StateType.TWO);
  thirdOriginator.SetData(99);
  myOriginator.Speak();
  anotherOriginator.Speak();
  thirdOriginator.Speak();
  // Restore our originator's state.
  myOriginator.RestoreMemento(memento);
  anotherOriginator.RestoreMemento(memento);
  thirdOriginator.RestoreMemento(memento);
  myOriginator.Speak();
  anotherOriginator.Speak();
  thirdOriginator.Speak();
  Console.ReadKey();
}
تا خط ۱۲، مراحل عادی کد نویسی را پیش رفته‌ایم. در خطوط ۱۳ تا ۱۵، داده را در Memento ذخیره میکنیم. در خطوط ۱۷ تا ۱۹، داده‌های اشیاء را با استفاده از متد SetData عوض میکنیم. در خطوط ۲۰ تا ۲۲ با متد Speak، مقدار value را نمایش میدهیم و در خطوط ۲۴ تا ۲۶، داده‌ها را Restore میکنیم و در آخر دوباره مقدار value را نمایش میدهیم.
برنامه را اجرا کنید .خروجی به شکل زیر خواهد بود:
Hello World! I'm in state ONE
Hola! I'm in state ONE
My value is 7
Goodbye! I'm in state TWO
Adios! I'm in state TWO
My value is 99
Hello World! I'm in state ONE
Hola! I'm in state ONE
My value is 7
اشتراک‌ها
دوره آموزشی Blazor

Welcome to this short introduction to Blazor! This new Microsoft framework uses a unique approach to leverage your existing C# and .NET skills to create single-page applications running in web browsers. The technology that makes this possible is called WebAssembly, an open standard supported directly by current browsers on desktop and mobile platforms. You write C# and Razor code instead of JavaScript, and the compiled app runs natively on the client.

Sample Source Code: https://github.com/DevExpress/blazor-training-samples  

دوره آموزشی Blazor
اشتراک‌ها
Visual Studio 2017 15.5.7 منتشر شد

Issues Fixed in this Release

Projects targeting .NET Core 2.1 or newer are not supported by Visual Studio 2017 version 15.5 .
Fixed issue where installation of the SDK for .NET Core 2.1 or newer would cause the option to create ASP.NET Core 2.0 Web applications to disappear .
Visual Studio 2017 15.5.7 منتشر شد
اشتراک‌ها
9.Visual Studio 2017 15.8 منتشر شد

These are the customer-reported issues addressed in 15.8.9:

9.Visual Studio 2017 15.8 منتشر شد
مطالب
بررسی الگوی Visitor در جاوا اسکریپت
این الگو اجازه‌ی تعریف کردن عملیاتی جدید را برای مجموعه‌ای از شیء‌ها، بدون تغیر دادن ساختار خود شیء‌ها، میدهد. همچنین اجازه‌ی جدا کردن کلاس را از منطقی که کلاس  پیاده سازی می‌کند، به ما میدهد.
عملیات بیشتری می‌توانند در شیء Visitor کپسوله سازی شوند. شیء‌ها می‌توانند یک متد visit داشته باشند که یک شیء Visitor را دریافت می‌کند. Visitor می‌تواند تغییرات مورد نیاز را ایجاد کند و عملیاتی را بر روی شیء‌هایی که دریافت کرده‌است، انجام دهد.

این الگو به توسعه دهندگان این اجازه را میدهد که کتابخانه‌ها (libraries)، فریم ورک‌ها (frameworks) و ... را گسترش دهند.


مثال: 

class Visitor {
    visit(item){}
}

class BookVisitor extends Visitor {
    visit(book) {
        var cost=0; 
        if(book.getPrice() > 50) 
        { 
            cost = book.getPrice()*0.50 
        } 
        else{
            cost = book.getPrice()
        }     
        console.log("Book name: "+ book.getName() + "\n" + "ID: " + book.getID() + "\n" + "cost: "+ cost); 
        return cost; 
    }
}

class Book{
    constructor(id,name,price){
        this.id = id
        this.name = name
        this.price = price
    }
    getPrice(){
        return this.price
    }
    getName(){
        return this.name
    }
    getID(){
        return this.id
    }
    accept(visitor){
        return visitor.visit(this)
    }
}

var visitor = new BookVisitor()
var book1 = new Book("#1234","lordOftheRings",80)
book1.accept(visitor)

در مثال بالا ما یک کتابفروشی داریم. کلاس Book برای نشان دادن یک کتاب در فروشگاه استفاده شده‌است. این کلاس همانند زیر تعریف شده‌است: 
class Book{
    constructor(id,name,price){
        this.id = id
        this.name = name
        this.price = price
    }
    //code...
}

یک کتاب خصوصیات زیر را دارد: 
  • id
  • name
  • price

هم چنین شامل توابع زیر می‌باشد:
getPrice(){
    return this.price
}

getName(){
    return this.name
}

getID(){
    return this.id
}

متد getPrice ، قیمت را برگشت میدهد، getName ، نام را برگشت میدهد و getID، شناسه‌ی کتاب را برگشت میدهد.

اکنون کتابفروشی یک تخفیف را برای کتاب‌هایی که هزینه‌ی آن‌ها بیشتر از 50 دلار است، معرفی می‌کند. در ادامه، می‌خواهیم یک عملیات دیگر را انجام دهیم و تخفیف را بر روی آن‌ها پیاده سازی کنیم. در اینجا از الگوی visitor استفاده خواهیم کرد. ما یک Visitor را معرفی می‌کنیم که کتابها را بازدید خواهد کرد و قیمت آن‌ها را به‌روزرسانی می‌کند. بنابراین شیء‌های کتاب باید تابعی داشته باشند که اجازه دهد visitor، آنها را بازدید (visit) کند و عملیات مد نظر را بر روی آن‌ها انجام دهد. برای این منظور، یک متد به نام accept  در کلاس Book  تعریف کرده‌ایم:
 
accept(visitor){
    return visitor.visit(this)
}

متد accept  یک شیء visitor را به عنوان یک آرگومان دریافت می‌کند و به آن اجازه میدهد که با فراخوانی کردن تابع visit خودش، کتاب جاری را بازدید (visit) کند (this اشاره به کتاب جاری دارد) .

اکنون اجازه دهید نگاهی به کلاس Visitor  داشته باشیم: 
class Visitor {
   visit(item){}
}

این کلاس، یک تابع به نام visit دارد و itemی را که می‌خواهد بازدید (visit ) کند، به عنوان پارامتر دریافت می‌کند. در این سناریو، می‌خواهیم که کتاب‌ها را بازدید (visit ) کنیم. از این رو، در ابتدا یک کلاس را به نام BookVisitor تعریف می‌کنیم که کلاس Visitor را extend می‌کند: 

class BookVisitor extends Visitor {
   visit(book) {
      var cost=0; 
      if(book.getPrice() > 50) 
      { 
         cost = book.getPrice()*0.50 
      } 
      else{
         cost = book.getPrice()
      }     
      console.log("Book name: "+ book.getName() + "\n" + "ID: " + book.getID() + "\n" + "cost: "+ cost); 
      return cost; 
   }
}

تابع visit، قیمت کتابی را که دارد بازدید می‌کند، بررسی می‌کند. اگر بزرگتر از 50 باشد، 50 درصد تخفیف را بر روی آن اعمال می‌کند؛ در غیر این صورت، قیمت به حالت قبلی خودش باقی می‌ماند. 

چه زمانی از این الگو استفاده کنیم:

  1. زمانیکه نیاز است عملیاتی مشابه، بر روی شیء‌های متفاوتی از یک data structure  انجام شود. 
  2. زمانیکه نیاز است عملیاتی خاص، بر روی شیء‌های متفاوتی از data structure انجام شود. 
  3. زمانیکه می‌خواهید توسعه پذیری را برای کتابخانه‌ها (libraries) یا فریم ورک‌ها (frameworks) اضافه کنید.