الگوهای طراحی (Design Patterns) راهحلهایی هستند برای مشکلات رایج در طراحی نرمافزار. این الگوها بهترین شیوههایی هستند که در صنعت نرمافزار به مرور زمان تکامل یافتهاند. در ادامه چند الگوی طراحی معروف با مثالهایی در زبان C# توضیح داده شدهاند:
معرفی کوتاه انواع الگوریتم های طراحی
Abstract Factory: خانواده هایی از اشیا که اعضای خانواده به یکدیگر مرتبط هستند را تولید می کند.
Adapter: اینترفیسی ایجاد می کند که کلاس هایی که با هم مرتبط نیستند بتوانند با یکدیگر کار کنند.
Bridge" جدا ساختن قسمت پیاده سازی از قسمت انتزاعی یک کلاس برای این که دو طرف بتوانند به راحتی و مستقلا تغییر کنند.
Builder: ساخت يک شی پيجيده را به گونه اي از نمايش آن مجزا مي کند که همان فرآيند ساخت مي تواند نمایش های متفاوتی ایجاد کند.
Chain of Responsibility: در قالب یک زنجیره از اشیا به درخواست کاربر پاسخ می دهد.
Command: مشخص می کند که یک عملیات(operation) چگونه انجام شود و انجام آن ها را مدیریت می کند.
Composite: اشیا را در ساختارهاي درختي ترکيب مي کند. Composite به کاربران اجازه مي دهد با اشیا منفرد و اشیا ترکيبي به طور يکسان برخورد کنند.
Decorator: مسؤوليت هاي اضافي را به طور ديناميک به يک شی ضميمه مي کند . Decorator ها جايگزيني انعطاف پذير جهت طبقه بندي فرعي براي توسعه عملکرد مهيا مي کنند .
Facade: اینترفیسي يکنواخت براي مجموعه ميانجي هاي موجود در يک کلاس فرعي مهيا مي کند . نماي خارجي، اینترفیس سطح بالاتري را تعريف مي کند که استفاده از سيستم فرعي را ساده تر مي کند .
Factory Method: يک اینترفیس جهت ايجاد يک شی تعيين مي کند ، ولي اجازه مي دهد کلاس هاي فرعي تصميم بگيرند کدام کلاس را معرفي کند
Flyweight: زمانی استفاده می شود که تعداد اشیا بسیار زیاد باشد و مدیریت آنها سخت باشد.
Interpreter: جهت تعریف گرامرهای یک زبان و تفسیر جملات استفاده می شود که تنها در طراحی کامپایلرها کاربرد دارد.
Iterator: شيوه اي جهت دسترسي به عناصر يک شی بهم پيوسته به طور متوالي تدارک مي بيند بدون اين که نمايش موجود را دچار مخاطره کند .
Mediator: شیئی را تعيين مي کند که چگونگي تعامل يک مجموعه اشیا را در یک محفظه قرار مي دهد. همچنین باعث می شود که اشیا به طور دو به دو کمتر با هم ارتباط داشته باشند و پدیده ی coupling کمتر شود.
Memento: حالت دروني يک شی را به گونه اي دقيق ذخیره می کند که بعدا بتوان شی را به اين حالت بازگرداند.
Observer: يک وابستگي يک به چند ميان اشیا را به گونه اي تعريف مي کند که هنگامي که يک شی تغيير کند کليه موارد وابسته به آن متوجه شده و به طور خودکار بهنگام سازي شوند .
Prototype: برای ساخت و کپی کردن شیئی جدید که خواص شی اصلی را داشته باشد.
Proxy: براي شی ديگر يک جانشين يا جاي گيرنده فراهم مي کند تا چگونگي دسترسي به آن را کنترل کند .
Singleton: تضمين مي کند که يک کلاس فقط يک نمونه داشته باشد ، و يک نمونه ي کلي جهت دسترسي به آن را مهيا کند .
State: به يک شی اجازه مي دهد هنگامي که حالت دروني آن تغيير کرد رفتار خود را عوض کند . به نظر مي رسد که شی کلاس خود را عوض مي کند .
Strategy: يک خانواده از الگوريتم ها را تعريف کرده ، هر يک را در پوشش قرار داده و آن ها را قابل تعویض مي سازد . استراتژي اجازه مي دهد الگوريتم به طور مستقل از کاربران که از آن استفاد مي کنند متفاوت باشد .
Template Method: اسکلت بندي الگوريتم در يک عمليات را تعريف کرده ، پیاده سازی بعضي مراحل را یه کلاس های فرعی می سپارد. همچنین به کلاس هاي فرعي مجال مي دهد بعضي مراحل يک الگوريتم را بدون تغيير ساختار الگوريتم دوباره تعريف کند .
Visitor: ويزيتور به شما مجال مي دهد عمليات جديد را بدون تغيير کلاس هاي عناصري که در آن کار مي کند تغيير دهيد .
1. الگوی Singleton (تکنمونه)
این الگو تضمین میکند که از یک کلاس فقط یک نمونه ایجاد شود و یک نقطه دسترسی جهانی به آن فراهم میکند.
public class Singleton
{
private static Singleton _instance;
private static readonly object _lock = new object();
private Singleton() { }
public static Singleton Instance
{
get
{
lock (_lock)
{
if (_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
}
}
}
2. الگوی Factory Method (متد کارخانهای)
این الگو یک رابط برای ایجاد یک شیء تعریف میکند اما به زیرکلاسها اجازه میدهد نوع شیء ایجاد شده را تغییر دهند.
public abstract class Product
{
public abstract string GetName();
}
public class ConcreteProductA : Product
{
public override string GetName() => "Product A";
}
public class ConcreteProductB : Product
{
public override string GetName() => "Product B";
}
public abstract class Creator
{
public abstract Product FactoryMethod();
}
public class ConcreteCreatorA : Creator
{
public override Product FactoryMethod() => new ConcreteProductA();
}
public class ConcreteCreatorB : Creator
{
public override Product FactoryMethod() => new ConcreteProductB();
}
3. الگوی Observer (ناظر)
این الگو وابستگی یک به چندی بین اشیاء تعریف میکند به طوری که وقتی وضعیت یک شیء تغییر کند، تمام وابستگان آن به طور خودکار بهروزرسانی شوند.
public interface IObserver
{
void Update();
}
public interface ISubject
{
void Attach(IObserver observer);
void Detach(IObserver observer);
void Notify();
}
public class ConcreteSubject : ISubject
{
private readonly List<IObserver> _observers = new List<IObserver>();
public void Attach(IObserver observer) => _observers.Add(observer);
public void Detach(IObserver observer) => _observers.Remove(observer);
public void Notify()
{
foreach (var observer in _observers)
{
observer.Update();
}
}
}
public class ConcreteObserver : IObserver
{
private readonly ConcreteSubject _subject;
public ConcreteObserver(ConcreteSubject subject)
{
_subject = subject;
_subject.Attach(this);
}
public void Update()
{
// واکنش به تغییر وضعیت موضوع
}
}
4. الگوی Strategy (استراتژی)
این الگو به شما اجازه میدهد یک خانواده از الگوریتمها را تعریف کنید، هر الگوریتم را در یک کلاس جداگانه قرار دهید، و بین آنها انتخاب کنید.
public interface IStrategy
{
void Execute();
}
public class ConcreteStrategyA : IStrategy
{
public void Execute()
{
Console.WriteLine("استراتژی A اجرا شد");
}
}
public class ConcreteStrategyB : IStrategy
{
public void Execute()
{
Console.WriteLine("استراتژی B اجرا شد");
}
}
public class Context
{
private IStrategy _strategy;
public void SetStrategy(IStrategy strategy)
{
_strategy = strategy;
}
public void ExecuteStrategy()
{
_strategy.Execute();
}
}
5. الگوی Decorator (تزئینکننده)
این الگو به شما اجازه میدهد تا رفتار یک شیء را بدون تغییر کلاس آن گسترش دهید.
public interface IComponent
{
string Operation();
}
public class ConcreteComponent : IComponent
{
public string Operation()
{
return "ConcreteComponent";
}
}
public abstract class Decorator : IComponent
{
protected IComponent _component;
public Decorator(IComponent component)
{
_component = component;
}
public virtual string Operation()
{
return _component.Operation();
}
}
public class ConcreteDecoratorA : Decorator
{
public ConcreteDecoratorA(IComponent component) : base(component) { }
public override string Operation()
{
return $"ConcreteDecoratorA({base.Operation()})";
}
}
public class ConcreteDecoratorB : Decorator
{
public ConcreteDecoratorB(IComponent component) : base(component) { }
public override string Operation()
{
return $"ConcreteDecoratorB({base.Operation()})";
}
}
6. الگوی Adapter (مبدل)
این الگو رابط یک کلاس را به رابط دیگری که مشتری انتظار دارد تبدیل میکند. این الگو به کلاسهایی که نمیتوانند با هم کار کنند اجازه میدهد تا با هم کار کنند.
public interface ITarget
{
string GetRequest();
}
public class Adaptee
{
public string GetSpecificRequest()
{
return "درخواست خاص Adaptee";
}
}
public class Adapter : ITarget
{
private readonly Adaptee _adaptee;
public Adapter(Adaptee adaptee)
{
_adaptee = adaptee;
}
public string GetRequest()
{
return $"این '{_adaptee.GetSpecificRequest()}' است";
}
}
7. الگوی Composite (ترکیبی)
این الگو به شما اجازه میدهد اشیاء را به ساختارهای درختی ترکیب کنید تا نمایش بخشیکل ایجاد شود. مشتری میتواند با اشیاء منفرد و ترکیبها به شکل یکنواختی رفتار کند.
public abstract class Component
{
protected string Name;
public Component(string name)
{
Name = name;
}
public abstract void Display(int depth);
}
public class Leaf : Component
{
public Leaf(string name) : base(name) { }
public override void Display(int depth)
{
Console.WriteLine(new string('-', depth) + Name);
}
}
public class Composite : Component
{
private readonly List<Component> _children = new List<Component>();
public Composite(string name) : base(name) { }
public void Add(Component component)
{
_children.Add(component);
}
public void Remove(Component component)
{
_children.Remove(component);
}
public override void Display(int depth)
{
Console.WriteLine(new string('-', depth) + Name);
foreach (Component component in _children)
{
component.Display(depth + 2);
}
}
}
// استفاده از الگوی Composite
var root = new Composite("Root");
root.Add(new Leaf("Leaf A"));
root.Add(new Leaf("Leaf B"));
var comp = new Composite("Composite X");
comp.Add(new Leaf("Leaf XA"));
comp.Add(new Leaf("Leaf XB"));
root.Add(comp);
root.Add(new Leaf("Leaf C"));
var leaf = new Leaf("Leaf D");
root.Add(leaf);
root.Remove(leaf);
root.Display(1);
8. الگوی Command (دستور)
این الگو یک درخواست را به عنوان یک شیء دربرمیگیرد و به شما اجازه میدهد پارامترهای مختلفی را برای درخواستها، صفبندی و اجرای آنها به طور غیرهمزمان نگه دارید.
public interface ICommand
{
void Execute();
}
public class Receiver
{
public void Action()
{
Console.WriteLine("عملیات اجرا شد");
}
}
public class ConcreteCommand : ICommand
{
private readonly Receiver _receiver;
public ConcreteCommand(Receiver receiver)
{
_receiver = receiver;
}
public void Execute()
{
_receiver.Action();
}
}
public class Invoker
{
private ICommand _command;
public void SetCommand(ICommand command)
{
_command = command;
}
public void ExecuteCommand()
{
_command.Execute();
}
}
// استفاده از الگوی Command
var receiver = new Receiver();
var command = new ConcreteCommand(receiver);
var invoker = new Invoker();
invoker.SetCommand(command);
invoker.ExecuteCommand();
9. الگوی Proxy (پراکسی)
این الگو یک جایگزین یا نگهبان برای دسترسی به یک شیء دیگر است. یک پراکسی میتواند کنترل دسترسی، نگهداری، یا بهبود کارایی را فراهم کند.
public interface ISubject
{
void Request();
}
public class RealSubject : ISubject
{
public void Request()
{
Console.WriteLine("RealSubject: درخواست را انجام میدهد.");
}
}
public class Proxy : ISubject
{
private RealSubject _realSubject;
public void Request()
{
if (_realSubject == null)
{
_realSubject = new RealSubject();
}
_realSubject.Request();
}
}
// استفاده از الگوی Proxy
var proxy = new Proxy();
proxy.Request();
10. الگوی Chain of Responsibility (زنجیره مسئولیت)
این الگو به یک درخواست اجازه میدهد تا توسط چندین شیء پردازش شود. هر شیء درخواست را به شیء بعدی در زنجیره انتقال میدهد.
public abstract class Handler
{
protected Handler successor;
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
public abstract void HandleRequest(int request);
}
public class ConcreteHandler1 : Handler
{
public override void HandleRequest(int request)
{
if (request == 1)
{
Console.WriteLine($"{this.GetType().Name} handled request {request}");
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
public class ConcreteHandler2 : Handler
{
public override void HandleRequest(int request)
{
if (request == 2)
{
Console.WriteLine($"{this.GetType().Name} handled request {request}");
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
// استفاده از الگوی Chain of Responsibility
var h1 = new ConcreteHandler1();
var h2 = new ConcreteHandler2();
h1.SetSuccessor(h2);
h1.HandleRequest(1);
h1.HandleRequest(2);
h1.HandleRequest(3);
11. الگوی Mediator (میانجی)
این الگو یک شیء را تعریف میکند که نحوه تعامل مجموعهای از اشیاء را کپسوله میکند. میانجی باعث کاهش وابستگیهای مستقیم بین اشیاء میشود و تعاملات را بهبود میبخشد.
public interface IMediator
{
void Notify(object sender, string ev);
}
public class ConcreteMediator : IMediator
{
private Component1 _component1;
private Component2 _component2;
public ConcreteMediator(Component1 component1, Component2 component2)
{
_component1 = component1;
_component1.SetMediator(this);
_component2 = component2;
_component2.SetMediator(this);
}
public void Notify(object sender, string ev)
{
if (ev == "A")
{
Console.WriteLine("Mediator reacts on A and triggers following operations:");
_component2.DoC();
}
else if (ev == "D")
{
Console.WriteLine("Mediator reacts on D and triggers following operations:");
_component1.DoB();
_component2.DoC();
}
}
}
public class BaseComponent
{
protected IMediator _mediator;
public BaseComponent(IMediator mediator = null)
{
_mediator = mediator;
}
public void SetMediator(IMediator mediator)
{
_mediator = mediator;
}
}
public class Component1 : BaseComponent
{
public void DoA()
{
Console.WriteLine("Component 1 does A.");
_mediator.Notify(this, "A");
}
public void DoB()
{
Console.WriteLine("Component 1 does B.");
_mediator.Notify(this, "B");
}
}
public class Component2 : BaseComponent
{
public void DoC()
{
Console.WriteLine("Component 2 does C.");
_mediator.Notify(this, "C");
}
public void DoD()
{
Console.WriteLine("Component 2 does D.");
_mediator.Notify(this, "D");
}
}
// استفاده از الگوی Mediator
var component1 = new Component1();
var component2 = new Component2();
var mediator = new ConcreteMediator(component1, component2);
component1.DoA();
component2.DoD();
12. الگوی State (وضعیت)
این الگو به یک شیء اجازه میدهد که رفتار خود را تغییر دهد وقتی وضعیت داخلیاش تغییر میکند. این الگو به نظر میرسد که شیء کلاس خود را تغییر داده است.
public interface IState
{
void Handle(Context context);
}
public class ConcreteStateA : IState
{
public void Handle(Context context)
{
Console.WriteLine("ConcreteStateA handles request.");
context.State = new ConcreteStateB();
}
}
public class ConcreteStateB : IState
{
public void Handle(Context context)
{
Console.WriteLine("ConcreteStateB handles request.");
context.State = new ConcreteStateA();
}
}
public class Context
{
private IState _state;
public Context(IState state)
{
_state = state;
}
public IState State
{
get { return _state; }
set
{
_state = value;
Console.WriteLine($"State changed to: {_state.GetType().Name}");
}
}
public void Request()
{
_state.Handle(this);
}
}
// استفاده از الگوی State
var context = new Context(new ConcreteStateA());
context.Request();
context.Request();
13. الگوی Template Method (روش قالب)
این الگو اسکلت یک الگوریتم را در یک متد تعریف میکند، در حالی که پیادهسازی برخی مراحل را به زیرکلاسها واگذار میکند. این الگو به زیرکلاسها اجازه میدهد تا مراحل خاصی از یک الگوریتم را بدون تغییر ساختار آن بازنویسی کنند.
public abstract class AbstractClass
{
public void TemplateMethod()
{
BaseOperation1();
RequiredOperation1();
BaseOperation2();
RequiredOperation2();
BaseOperation3();
}
protected void BaseOperation1()
{
Console.WriteLine("AbstractClass: انجام عملیات پایه 1");
}
protected void BaseOperation2()
{
Console.WriteLine("AbstractClass: انجام عملیات پایه 2");
}
protected void BaseOperation3()
{
Console.WriteLine("AbstractClass: انجام عملیات پایه 3");
}
protected abstract void RequiredOperation1();
protected abstract void RequiredOperation2();
}
public class ConcreteClass1 : AbstractClass
{
protected override void RequiredOperation1()
{
Console.WriteLine("ConcreteClass1: پیادهسازی عملیات 1");
}
protected override void RequiredOperation2()
{
Console.WriteLine("ConcreteClass1: پیادهسازی عملیات 2");
}
}
public class ConcreteClass2 : AbstractClass
{
protected override void RequiredOperation1()
{
Console.WriteLine("ConcreteClass2: پیادهسازی عملیات 1");
}
protected override void RequiredOperation2()
{
Console.WriteLine("ConcreteClass2: پیادهسازی عملیات 2");
}
}
// استفاده از الگوی Template Method
AbstractClass concreteClass1 = new ConcreteClass1();
concreteClass1.TemplateMethod();
AbstractClass concreteClass2 = new ConcreteClass2();
concreteClass2.TemplateMethod();
14. الگوی Iterator (گردشگر)
این الگو روشی را برای دسترسی به عناصر یک مجموعه به صورت ترتیبی بدون افشای نمایش زیرین آن مجموعه فراهم میکند.
public interface IIterator
{
bool HasNext();
object Next();
}
public interface IAggregate
{
IIterator CreateIterator();
}
public class ConcreteAggregate : IAggregate
{
private readonly List<object> _items = new List<object>();
public IIterator CreateIterator()
{
return new ConcreteIterator(this);
}
public int Count => _items.Count;
public object this[int index]
{
get => _items[index];
set => _items.Insert(index, value);
}
}
public class ConcreteIterator : IIterator
{
private readonly ConcreteAggregate _aggregate;
private int _current = 0;
public ConcreteIterator(ConcreteAggregate aggregate)
{
_aggregate = aggregate;
}
public bool HasNext()
{
return _current < _aggregate.Count;
}
public object Next()
{
return HasNext() ? _aggregate[_current++] : null;
}
}
// استفاده از الگوی Iterator
ConcreteAggregate aggregate = new ConcreteAggregate();
aggregate[0] = "Item A";
aggregate[1] = "Item B";
aggregate[2] = "Item C";
IIterator iterator = aggregate.CreateIterator();
while (iterator.HasNext())
{
object item = iterator.Next();
Console.WriteLine(item);
}
15. الگوی Memento (یادگار)
این الگو بدون افشای جزئیات پیادهسازی داخلی آن، حالت داخلی یک شیء را ذخیره و بازیابی میکند.
public class Memento
{
public string State { get; }
public Memento(string state)
{
State = state;
}
}
public class Originator
{
public string State { get; set; }
public Memento SaveStateToMemento()
{
return new Memento(State);
}
public void GetStateFromMemento(Memento memento)
{
State = memento.State;
}
}
public class Caretaker
{
private readonly List<Memento> _mementoList = new List<Memento>();
public void Add(Memento state)
{
_mementoList.Add(state);
}
public Memento Get(int index)
{
return _mementoList[index];
}
}
// استفاده از الگوی Memento
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.State = "State #1";
originator.State = "State #2";
caretaker.Add(originator.SaveStateToMemento());
originator.State = "State #3";
caretaker.Add(originator.SaveStateToMemento());
originator.State = "State #4";
Console.WriteLine("Current State: " + originator.State);
originator.GetStateFromMemento(caretaker.Get(0));
Console.WriteLine("First saved State: " + originator.State);
originator.GetStateFromMemento(caretaker.Get(1));
Console.WriteLine("Second saved State: " + originator.State);
16. الگوی Flyweight (وزن مگس)
این الگو از اشتراکگذاری برای پشتیبانی از مقادیر بزرگ اشیاء ریزدانه استفاده میکند. در صورت امکان، دادههای مشترک بین اشیاء را به اشتراک میگذارد تا استفاده از حافظه را کاهش دهد.
public class Flyweight
{
private readonly string _intrinsicState;
public Flyweight(string intrinsicState)
{
_intrinsicState = intrinsicState;
}
public void Operation(string extrinsicState)
{
Console.WriteLine($"Flyweight: Intrinsic = {_intrinsicState}, Extrinsic = {extrinsicState}");
}
}
public class FlyweightFactory
{
private readonly Dictionary<string, Flyweight> _flyweights = new Dictionary<string, Flyweight>();
public Flyweight GetFlyweight(string key)
{
if (!_flyweights.ContainsKey(key))
{
_flyweights[key] = new Flyweight(key);
}
return _flyweights[key];
}
}
// استفاده از الگوی Flyweight
FlyweightFactory factory = new FlyweightFactory();
Flyweight flyweight1 = factory.GetFlyweight("A");
Flyweight flyweight2 = factory.GetFlyweight("A");
Flyweight flyweight3 = factory.GetFlyweight("B");
flyweight1.Operation("First Call");
flyweight2.Operation("Second Call");
flyweight3.Operation("Third Call");
17. الگوی Builder (سازنده)
این الگو فرآیند ساخت یک شیء پیچیده را از نمایش نهایی آن جدا میکند، به طوری که همان فرآیند ساخت میتواند نمایشهای مختلفی داشته باشد.
18. الگوی Visitor (بازدیدکننده)
این الگو به شما اجازه میدهد که یک عملیات جدید را بدون تغییر کلاسهای اشیاء بر روی یک مجموعه از اشیاء اعمال کنید.
public interface IVisitor
{
void Visit(ElementA element);
void Visit(ElementB element);
}
public interface IElement
{
void Accept(IVisitor visitor);
}
public class ElementA : IElement
{
public void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
public string OperationA()
{
return "ElementA";
}
}
public class ElementB : IElement
{
public void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
public string OperationB()
{
return "ElementB";
}
}
public class ConcreteVisitor1 : IVisitor
{
public void Visit(ElementA element)
{
Console.WriteLine($"{element.OperationA()} + ConcreteVisitor1");
}
public void Visit(ElementB element)
{
Console.WriteLine($"{element.OperationB()} + ConcreteVisitor1");
}
}
public class ConcreteVisitor2 : IVisitor
{
public void Visit(ElementA element)
{
Console.WriteLine($"{element.OperationA()} + ConcreteVisitor2");
}
public void Visit(ElementB element)
{
Console.WriteLine($"{element.OperationB()} + ConcreteVisitor2");
}
}
// استفاده از الگوی Visitor
List<IElement> elements = new List<IElement>
{
new ElementA(),
new ElementB()
};
ConcreteVisitor1 visitor1 = new ConcreteVisitor1();
ConcreteVisitor2 visitor2 = new ConcreteVisitor2();
foreach (var element in elements)
{
element.Accept(visitor1);
element.Accept(visitor2);
}
19. الگوی Bridge (پل)
این الگو پیادهسازیها را از رابطها جدا میکند، به طوری که هر دو بخش میتوانند مستقل از یکدیگر تغییر کنند.
public interface IImplementation
{
string OperationImplementation();
}
public class ConcreteImplementationA : IImplementation
{
public string OperationImplementation()
{
return "ConcreteImplementationA: نتیجه در پلتفرم A.";
}
}
public class ConcreteImplementationB : IImplementation
{
public string OperationImplementation()
{
return "ConcreteImplementationB: نتیجه در پلتفرم B.";
}
}
public abstract class Abstraction
{
protected IImplementation _implementation;
protected Abstraction(IImplementation implementation)
{
_implementation = implementation;
}
public virtual string Operation()
{
return "Abstraction: پایه عملیات با:\n" +
_implementation.OperationImplementation();
}
}
public class ExtendedAbstraction : Abstraction
{
public ExtendedAbstraction(IImplementation implementation) : base(implementation)
{ }
public override string Operation()
{
return "ExtendedAbstraction: عملیات گسترده با:\n" +
base.Operation();
}
}
// استفاده از الگوی Bridge
IImplementation implementationA = new ConcreteImplementationA();
Abstraction abstraction = new ExtendedAbstraction(implementationA);
Console.WriteLine(abstraction.Operation());
IImplementation implementationB = new ConcreteImplementationB();
abstraction = new ExtendedAbstraction(implementationB);
Console.WriteLine(abstraction.Operation());
20. الگوی Facade (نما)
این الگو یک رابط ساده شده برای یک سیستم پیچیده فراهم میکند. این الگو باعث میشود که استفاده از سیستمهای پیچیده آسانتر شود.
public class Subsystem1
{
public string Operation1()
{
return "Subsystem1: آماده عملیات";
}
public string OperationN()
{
return "Subsystem1: انجام عملیات";
}
}
public class Subsystem2
{
public string Operation1()
{
return "Subsystem2: آماده عملیات";
}
public string OperationZ()
{
return "Subsystem2: انجام عملیات";
}
}
public class Facade
{
protected Subsystem1 _subsystem1;
protected Subsystem2 _subsystem2;
public Facade(Subsystem1 subsystem1, Subsystem2 subsystem2)
{
_subsystem1 = subsystem1;
_subsystem2 = subsystem2;
}
public string Operation()
{
string result = "Facade در حال هماهنگی زیرسیستمها:\n";
result += _subsystem1.Operation1() + "\n";
result += _subsystem1.OperationN() + "\n";
result += _subsystem2.Operation1() + "\n";
result += _subsystem2.OperationZ();
return result;
}
}
// استفاده از الگوی Facade
Subsystem1 subsystem1 = new Subsystem1();
Subsystem2 subsystem2 = new Subsystem2();
Facade facade = new Facade(subsystem1, subsystem2);
Console.WriteLine(facade.Operation());
21. الگوی Interpreter (مفسر)
این الگو یک زبان را تعریف و نحوه تفسیر جملات در این زبان را تعیین میکند. برای مثال، یک ماشینحساب ساده که از این الگو استفاده میکند.
public interface IExpression
{
int Interpret();
}
public class Number : IExpression
{
private readonly int _number;
public Number(int number)
{
_number = number;
}
public int Interpret()
{
return _number;
}
}
public class Add : IExpression
{
private readonly IExpression _leftExpression;
private readonly IExpression _rightExpression;
public Add(IExpression leftExpression, IExpression rightExpression)
{
_leftExpression = leftExpression;
_rightExpression = rightExpression;
}
public int Interpret()
{
return _leftExpression.Interpret() + _rightExpression.Interpret();
}
}
public class Subtract : IExpression
{
private readonly IExpression _leftExpression;
private readonly IExpression _rightExpression;
public Subtract(IExpression leftExpression, IExpression rightExpression)
{
_leftExpression = leftExpression;
_rightExpression = rightExpression;
}
public int Interpret()
{
return _leftExpression.Interpret() - _rightExpression.Interpret();
}
}
// استفاده از الگوی Interpreter
IExpression expression = new Add(new Number(10), new Subtract(new Number(20), new Number(5)));
Console.WriteLine($"نتیجه: {expression.Interpret()}");
22. الگوی Prototype (نمونه اولیه)
این الگو به اشیاء اجازه میدهد که از نمونههای اولیه خود کپی شوند و تغییرات را در نمونهها ایجاد کنند.
public abstract class Prototype
{
public string Id { get; }
public Prototype(string id)
{
Id = id;
}
public abstract Prototype Clone();
}
public class ConcretePrototype1 : Prototype
{
public ConcretePrototype1(string id) : base(id) { }
public override Prototype Clone()
{
return (Prototype)MemberwiseClone();
}
}
public class ConcretePrototype2 : Prototype
{
public ConcretePrototype2(string id) : base(id) { }
public override Prototype Clone()
{
return (Prototype)MemberwiseClone();
}
}
// استفاده از الگوی Prototype
ConcretePrototype1 prototype1 = new ConcretePrototype1("I");
ConcretePrototype1 clone1 = (ConcretePrototype1)prototype1.Clone();
Console.WriteLine($"Clone1 ID: {clone1.Id}");
ConcretePrototype2 prototype2 = new ConcretePrototype2("II");
ConcretePrototype2 clone2 = (ConcretePrototype2)prototype2.Clone();
Console.WriteLine($"Clone2 ID: {clone2.Id}");
23. الگوی Mediator (میانجی)
این الگو تعاملات پیچیده بین مجموعهای از اشیاء را با معرفی یک شیء میانجی ساده میکند.
public interface IMediator
{
void Notify(object sender, string ev);
}
public class ConcreteMediator : IMediator
{
private Component1 _component1;
private Component2 _component2;
public ConcreteMediator(Component1 component1, Component2 component2)
{
_component1 = component1;
_component1.SetMediator(this);
_component2 = component2;
_component2.SetMediator(this);
}
public void Notify(object sender, string ev)
{
if (ev == "A")
{
Console.WriteLine("Mediator reacts on A and triggers following operations:");
_component2.DoC();
}
else if (ev == "D")
{
Console.WriteLine("Mediator reacts on D and triggers following operations:");
_component1.DoB();
_component2.DoC();
}
}
}
public class BaseComponent
{
protected IMediator _mediator;
public BaseComponent(IMediator mediator = null)
{
_mediator = mediator;
}
public void SetMediator(IMediator mediator)
{
_mediator = mediator;
}
}
public class Component1 : BaseComponent
{
public void DoA()
{
Console.WriteLine("Component 1 does A.");
_mediator.Notify(this, "A");
}
public void DoB()
{
Console.WriteLine("Component 1 does B.");
_mediator.Notify(this, "B");
}
}
public class Component2 : BaseComponent
{
public void DoC()
{
Console.WriteLine("Component 2 does C.");
_mediator.Notify(this, "C");
}
public void DoD()
{
Console.WriteLine("Component 2 does D.");
_mediator.Notify(this, "D");
}
}
// استفاده از الگوی Mediator
Component1 component1 = new Component1();
Component2 component2 = new Component2();
new ConcreteMediator(component1, component2);
Console.WriteLine("Client triggers operation A.");
component1.DoA();
Console.WriteLine();
Console.WriteLine("Client triggers operation D.");
component2.DoD();
1. تعریف مدلهای داده
ابتدا، مدلهای داده را تعریف میکنیم. فرض کنید که ما یک موجودیت ساده به نام Product داریم:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
2. تعریف رابط Repository
یک رابط Repository تعریف میکنیم که عملیات پایهای را مشخص میکند:
public class Repository<T> : IRepository<T> where T : class
{
private readonly DbContext _context;
private readonly DbSet<T> _dbSet;
public Repository(DbContext context)
{
_context = context;
_dbSet = context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _dbSet.ToList();
}
public T GetById(int id)
{
return _dbSet.Find(id);
}
public void Insert(T entity)
{
_dbSet.Add(entity);
}
public void Update(T entity)
{
_dbSet.Attach(entity);
_context.Entry(entity).State = EntityState.Modified;
}
public void Delete(int id)
{
T entity = _dbSet.Find(id);
if (entity != null)
{
_dbSet.Remove(entity);
}
}
public void Save()
{
_context.SaveChanges();
}
}
4. استفاده از Repository
در نهایت، میتوانیم از این الگو در لایه سرویس یا کنترلر استفاده کنیم. فرض کنید ما از ASP.NET Core MVC استفاده میکنیم:
public class ProductsController : Controller
{
private readonly IRepository<Product> _repository;
public ProductsController(IRepository<Product> repository)
{
_repository = repository;
}
public IActionResult Index()
{
var products = _repository.GetAll();
return View(products);
}
public IActionResult Details(int id)
{
var product = _repository.GetById(id);
if (product == null)
{
return NotFound();
}
return View(product);
}
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Product product)
{
if (ModelState.IsValid)
{
_repository.Insert(product);
_repository.Save();
return RedirectToAction(nameof(Index));
}
return View(product);
}
public IActionResult Edit(int id)
{
var product = _repository.GetById(id);
if (product == null)
{
return NotFound();
}
return View(product);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, Product product)
{
if (id != product.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_repository.Update(product);
_repository.Save();
}
catch (DbUpdateConcurrencyException)
{
if (!_repository.GetAll().Any(e => e.Id == id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(product);
}
public IActionResult Delete(int id)
{
var product = _repository.GetById(id);
if (product == null)
{
return NotFound();
}
return View(product);
}
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(int id)
{
_repository.Delete(id);
_repository.Save();
return RedirectToAction(nameof(Index));
}
}
5. تنظیمات Dependency Injection
در نهایت، باید تنظیمات وابستگی را در Startup.cs برای استفاده از Repository اضافه کنید:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
services.AddControllersWithViews();
}
این الگو باعث میشود که منطق دسترسی به دادهها از منطق تجاری جدا شده و همچنین کد تستپذیرتر و قابل نگهداریتر باشد.