رادکام
الگوی طراحی Proxy برای ایجاد اشیایی استفاده می شود که در اصل آنها ایجاد و دسترسی به اشیاء دیگر را کنترل می کنند. پروکسی غالباً یک شیء کوچک (عمومی) است که به دنبال یک موضوع پیچیده تر (خصوصی) می رود که به مجرد مشخص شدن و اتفاق افتادن شرایط خاص فعال می شود.
تعیین کننده دسترسی | تاثیر | پیش فرض برای |
private | در متد یا نوعی که در آن اعلام شده است قابل دسترس است | اعضای کلاسها و استراکت ها؛ انواع تو در تو |
internal | در داخل اسمبلی قابل دسترسی است | انواع غیر تو در تو |
protected | در یک کلاس و کلاسهای مشتق شده آن قابل دسترسی است | - |
protected internal | در یک کلاس ، کلاسهای مشتق شده آن یا اسمبلی قابل دسترسی است | - |
public | در همه جا قابل دسترسی است | Enumartion ها و رابط ها |
public class Proxy : ISubject
{
Subject subject;
public string Request()
{
// A virtual proxy creates the object only on its first method call
if (subject == null)
subject = new Subject();
return subject.Request();
}
}
کلاینت هر زمان که بخواهد می تواند با ایجاد یک نوع از پروکسی، از آن
استفاده کند. از آنجایی که از یک ایجاد کننده (Constructor) پیش فرض
استفاده می شود، ارجاع به کلاس Subject در این لحظه ایجاد نمی شود. و فقط
زمانی که متد Request فراخوانی می شود، ارجاع به کلاس Subject بررسی می
شود، اگر Null باشد، یک نمونه شی از آن ایجاد می شود.
کد کامل مثال اشاره شده در زیر آورده شده است، این مثال بر این نکته تاکید
دارد که تمام نمونه های موجود ایجاد شده توسط کلاینت، از نوع اینترفیس
ISubject می باشند. این بدان معنی است که، برای دسترسی به عملیات
مازاد و اضافه در کلاس پروکسی، مانند اعتبار سنجی، باید از کلاس
ISubject نمونه سازی کنیم. در مثال زیر پروکسی دومی نیز به نام
ProtectionProxy وجود دارد. این پروکسی مستقل از پروکسی ابتدایی است، زمانی
که شیء ای از کلاس ProtectionProxy ایجاد می شود. تمام درخواست های ابتدایی
با دستورالعمل های احراز هویت برآورده و اجرا می شوند. در این مثال، احراز
هویت یک متدی مستقل و جداگانه است که باید فراخوانی شود. در مثال بعدی،
ثبت نام و تایید اعتبار بعد از فراخوانی درخواست به صورت خودکار شروع می
شود.
using System;
// Proxy Pattern Judith Bishop Dec 2006
// Shows virtual and protection proxies
class SubjectAccessor {
public interface ISubject {
string Request();
}
private class Subject {
public string Request() {
return "Subject Request " + "Choose left door\n";
}
}
public class Proxy : ISubject {
Subject subject;
public string Request() {
// A virtual proxy creates the object only on its first method call
if (subject == null) {
Console.WriteLine("Subject inactive");
subject = new Subject();
}
Console.WriteLine("Subject active");
return "Proxy: Call to " + subject.Request();
}
}
public class ProtectionProxy : ISubject {
// An authentication proxy first asks for a password
Subject subject;
string password = "Abracadabra";
public string Authenticate (string supplied) {
if (supplied!=password)
return "Protection Proxy: No access";
else
subject = new Subject();
return "Protection Proxy: Authenticated";
}
public string Request() {
if (subject==null)
return "Protection Proxy: Authenticate first";
else return "Protection Proxy: Call to "+
subject.Request();
}
}
}
class Client : SubjectAccessor {
static void Main() {
Console.WriteLine("Proxy Pattern\n");
ISubject subject = new Proxy();
Console.WriteLine(subject.Request());
Console.WriteLine(subject.Request());
ProtectionProxy subject = new ProtectionProxy();
Console.WriteLine(subject.Request());
Console.WriteLine((subject as ProtectionProxy).Authenticate("Secret"));
Console.WriteLine((subject as ProtectionProxy).Authenticate("Abracadabra"));
Console.WriteLine(subject.Request());
}
}
/* Output
Proxy Pattern
Subject inactive
Subject active
Proxy: Call to Subject Request Choose left door
Subject active
Proxy: Call to Subject Request Choose left door
Protection Proxy: Authenticate first
Protection Proxy: No access
Protection Proxy: Authenticated
Protection Proxy: Call to Subject Request Choose left door
*/
این برنامه با یک کلاس به نام SubjectAccessor محصور شده است، که این کار
برای گروه بندی کلاس های پروکسی و Subject انجام شده است. اینترفیس و
کلاس های پروکسی همه به صورت public تعریف شده اند، بنابراین، خود آنها و
اعضای آنها که به صورت عمومی تعریف شده اند، همه به طور کامل در دسترس
کلاینت (برنامه استفاده کننده) قرار می گیرند. هدف از ایجاد کلاس های
پروکسی Virtual و Protected ایجاد یک دسترسی مشخص به کلاس Subject است. به
همین دلیل است که کلاس Subject به صورت private تعریف شده است و متد
Request آن public است، اما این متد فقط برای کلاس هایی قابل دسترس است که
می توانند خود کلاس را ببینند، مانند کلاس های داخل SubjectAccessor.
یک گروه بندی عمومی
تر برای کلاس های پروکسی و Subject می تواند Namespace هایی باشد که تعریف
می کنیم، اما کلاس هایی که درون NameSpace ها قرار دارند نمی توانند
به صورت private تعریف شوند.
کد زیر را به متد main اضافه کنید:
ISubject test = new Subject();
کدی که در سمت کلاینت نوشته شده است کامپایل نخواهد شد، زیرا کد های برنامه به گونه ای نوشته شده است که فقط می توانیم از کلاس های Proxy نمونه بسازیم. با این حال اگر خاصیت private بودن کلاس Subject را حذف کنیم می توانیم از آن نیز نمونه بسازیم. دلیل این کار این است که برای دستری به کلاس های موجود در SubjectAccessor، کلاینت از آنها ارث بری می کند، و با این کار به اعضای داخلی آن دسترسی پیدا می کنند. یک روش جایگزین برای برنامه نوشته شده ، در یک تمرین پیش رو ، مورد بحث قرار خواهد گرفت.
private class SpaceBook
{
static SortedList< string,RealSpaceBook> community = new SortedList< string,RealSpaceBook>(100);
string pages;
string name;
string gap = "\n\t\t\t\t";
static public bool IsUnique (string name)
{
return community.ContainsKey(name);
}
internal SpaceBook (string n)
{
name = n;
community [n] = this;
}
internal void Add(string s)
{
pages += gap+s;
Console.WriteLine(gap+"======== "+name+"'s SpaceBook =========");
Console.WriteLine(pages);
Console.WriteLine(gap+"==========================");
}
internal void Add(string friend, string message)
{
community[friend].Add(message);
}
internal void Poke (string who, string friend)
{
community[who].pages += gap + friend + " poked you";
}
}
کلاس Spacebook فهرستی استاتیک از همه کاربران فعلی را نگهداری می
کند. ما از کلاس از پیش تعبیه شده SortedList که در فضای نام
System.Collections.Generic قرار دارد استفاده می کنیم و یک فهرست از اعضا
و نام کاربر به عنوان یک رشته متنی (string) ایجاد می کنیم. در متد
سازنده کلاس می بینیم که شیء Spacebook در یک Collection با نام داده
شده به عنوان پارامتر متد سازنده قرار گرفته است. دو متذ Add نیز وجود دارد
که: یکی برای اضافه کردن کاربر و دیگری برای اضافه کردن صفحات کاربر. سپس
متد محبوب poke قرار دارد که یک پیام ثابت را در صفحه یک کاربر دیگر درج می
کند.کلاس Spacebook یک متد public دارد که شاید وجود آن غیر منتظره و عجیب به نظر برسد. متد استاتیک Unique، که بررسی می کند که یک اسم قبلا مورد استفاده قرار گرفته است یا نه. این متد ما را قادر می سازد که فهرست انجمن ها را به طور کامل خصوصی نگهداری کنیم(که به طور پیش فرض درون کلاس است). حال به سراغ کلاینت می رویم. کلاینت چند تا فعالیت را توسط Tom و Judith انجام می دهد.
// The Client
class ProxyPattern : SpaceBookSystem
{
static void Main ( )
{
MySpaceBook me = new MySpaceBook( );
me.Add("Hello world");
me.Add("Today I worked 18 hours");
MySpaceBook tom = new MySpaceBook( );
tom.Poke("Judith");
tom.Add("Judith","Poor you");
tom.Add("Off to see the Lion King tonight");
}
}
اولین کاربر، که ما از Judith استفاده می کنیم، یک MySpaceBook (نه یک
SpaceBook) را ایجاد کرده، دو پیام به آن اضافه می کند. سپس تام نیز
یک MySpaceBook ایجاد کرده و یک اشاره به Judith می کند و سپس یک
پیام به صفحه Judith و یک پیام به صفحه خودش اضافه می کند. توجه داشته
باشید که نه کلاینت و نه سیستم اصلی SpaceBook هیچ کدی برای اعتبار سنجی
ندارند. این کار فقط در Proxy اتفال می افتد که در اینجا به وضوح مشخص است
که همان کلاس MySpaceBook است. خروجی کد کلاینت قبلی چنین خواهد بود:Let's register you for SpaceBook
All SpaceBook names must be unique
Type in a user name: Judith
Type in a password: haha
Thanks for registering with SpaceBook
Welcome Judith. Please type in your password: haha
Logged into SpaceBook
======== Judith's SpaceBook =========
Hello world
==================================
======== Judith's SpaceBook =========
Hello world
Today I worked 18 hours
==================================
Let's register you for SpaceBook
All SpaceBook names must be unique
Type in a user name: Tom
Type in a password: yey
Thanks for registering with SpaceBook
Welcome Tom. Please type in your password: yey
Logged into SpaceBook
======== Judith's SpaceBook =========
Hello world
Today I worked 18 hours
Tom poked you
eTom said: Poor you
==================================
======== Tom's SpaceBook =========
Off to see the Lion King tonight
==================================
ما می توانیم بین خروجی که خود کلاس SpaceBook تولید می کند و درون
خطوط کشیده شده قرار گرفته است و همچنیم فعل و انفعلاتی که توسط کلاس
های Proxy صورت گرفته است تمایز قائل شویم. کلاس SpaceBook متد سازنده ای
ندارد. جدا از گرفتن مرجع از کلاس، وقتی کلاینت یک نمونه از Spacebook را
ایجاد می کند، اتفاقی در برنامه نمی افتد. قلب تپنده کلاس Proxy در بخش زیر
است:public void Add(string message)
{
Check( );
if (loggedIn) mySpaceBook.Add(message);
}
void Check( )
{
if (!loggedIn)
{
if (password==null)
Register( );
if (mySpaceBook == null)
Authenticate( );
}
}
اولین نقطه ارتباط با کلاینت، استفاده از متد Add است. متد Add بلادرنگ
وضعیت کاربر را بررسی می کند، و کاربر را در مسیر ثبت نام و تخصیص رمز عبور
راهنمایی می کند، و سپس عمل احراز هویت را با استفاده از رمز عبور ارایه
شده انجام می دهد. متد Check نیز توسط یک متد Add و Pock دیگری فراخوانی می
شود. حال بعد از این همه توضیح و تعریف، می توانیم کل کد ها را یکجا داشته
باشیم.
using System;
using System.Collections.Generic;
// Proxy Pattern Example Judith Bishop Aug 2007
// Sets up a SpaceBook page with registration and authentication
class SpaceBookSystem
{
// The Subject
private class SpaceBook
{
static SortedList <string,spacebook> community = new SortedList <string,spacebook> (100);
string pages;
string name;
string gap = "\n\t\t\t\t";
static public bool IsUnique (string name) {
return community.ContainsKey(name);
}
internalSpaceBook (string n)
{
name = n;
community [n] = this;
}
internal void Add(string s)
{
pages += gap+s;
Console.Write(gap+"======== "+name+"'s SpaceBook =========");
Console.Write(pages);
Console.WriteLine(gap+"===================================");
}
internal void Add(string friend, string message)
{
community[friend].Add(message);
}
internal void Poke (string who, string friend)
{
community[who].pages += gap + friend + " poked you";
}
}
// The Proxy
public class MySpaceBook
{
// Combination of a virtual and authentication proxy
SpaceBook mySpaceBook;
string password;
string name;
bool loggedIn = false;
void Register ( )
{
Console.WriteLine("Let's register you for SpaceBook");
do
{
Console.WriteLine("All SpaceBook names must be unique");
Console.Write("Type in a user name: ");
name = Console.ReadLine( );
} while (SpaceBook.Unique(name));
Console.Write("Type in a password: ");
password = Console.ReadLine( );
Console.WriteLine("Thanks for registering with SpaceBook");
}
bool Authenticate ( )
{
Console.Write("Welcome "+name+". Please type in your password: ");
string supplied = Console.ReadLine( );
if (supplied==password)
{
loggedIn = true;
Console.WriteLine("Logged into SpaceBook");
if (mySpaceBook == null)
mySpaceBook = new SpaceBook(name);
return true;
}
Console.WriteLine("Incorrect password");
return false;
}
public void Add(string message)
{
Check( );
if (loggedIn) mySpaceBook.Add(message);
}
public void Add(string friend, string message)
{
Check( );
if (loggedIn)
mySpaceBook.Add(friend, name + " said: "+message);
}
public void Poke(string who)
{
Check( );
if (loggedIn)
mySpaceBook.Poke(who,name);
}
void Check( )
{
if (!loggedIn)
{
if (password==null)
Register( );
if (mySpaceBook == null)
Authenticate( );
}
}
}
// The Client
class ProxyPattern : SpaceBookSystem
{
static void Main ( )
{
MySpaceBook me = new MySpaceBook( );
me.Add("Hello world");
me.Add("Today I worked 18 hours");
MySpaceBook tom = new MySpaceBook( );
tom.Poke("Judith");
tom.Add("Judith","Poor you");
tom.Add("Off to see the Lion King tonight");
}
}
/* Output
Let's register you for SpaceBook
All SpaceBook names must be unique
Type in a user name: Judith
Type in a password: haha
Thanks for registering with SpaceBook
Welcome Judith. Please type in your password: haha
Logged into SpaceBook
======== Judith's SpaceBook =========
Hello world
==================================
======== Judith's SpaceBook =========
Hello world
Today I worked 18 hours
==================================
Let's register you for SpaceBook
All SpaceBook names must be unique
Type in a user name: Tom
Type in a password: yey
Thanks for registering with SpaceBook
Welcome Tom. Please type in your password: yey
Logged into SpaceBook
======== Judith's SpaceBook =========
Hello world
Today I worked 18 hours
Tom poked you
eTom said: Poor you
==================================
======== Tom's SpaceBook =========
Off to see the Lion King tonight
==================================
*/</string,spacebook></string,spacebook>
توجه کنید که در این برنامه نیازی به اینترفیس ISubject وجود ندارد.
کلاس های SpaceBook و MySpaceBook که درون SpaceBookSystem استقرار دارند،
تعامل مابین کلاس ها و متد ها را توسط تنظیم کننده های سطوح دسترسی و
عمل تجمیع (کلاس MySpaceBook یک ارجاع به کلاس SpaceBook دارد) انجام
می دهند.4,325بازدید
دیدگاه کاربران
هنوز دیدگاهی ثبت نشده است.
شما میتوانید درباره این مقاله، دیدگاه خود را ثبت کنید.