title | shortTitle | category | language | tag | |
---|---|---|---|---|---|
Command |
Command |
Behavioral |
ar |
|
- إجراء
- معاملة
يُغلف نمط التصميم Command الطلب ككائن، مما يسمح بتمرير العملاء مع قوائم الانتظار، الطلبات، والعمليات. كما يدعم أيضًا التراجع عن العمليات.
يوجد ساحر يلقي تعويذات على عفريت. يتم تنفيذ التعويذات على العفريت واحدة تلو الأخرى. التعويذة الأولى تصغر العفريت والتعويذة الثانية تجعله غير مرئي. بعد ذلك، يقوم الساحر بالتراجع عن التعويذات واحدة تلو الأخرى. كل تعويذة هي كائن أمر يمكن التراجع عنها.
تخزين الطلبات ككائنات أمر يسمح بتنفيذ الإجراء أو التراجع عنه في وقت لاحق.
في البرمجة الكائنية التوجه، نمط الأمر هو نمط تصميم سلوكي حيث يتم استخدام كائن لتغليف كافة المعلومات اللازمة لتنفيذ إجراء أو تحفيز حدث في وقت لاحق.
إليك الكود البرمجي مع الساحر Wizard
والعفريت Goblin
. دعونا نبدأ بفئة الساحر Wizard
.
@Slf4j
public class Wizard {
private final Deque<Runnable> undoStack = new LinkedList<>();
private final Deque<Runnable> redoStack = new LinkedList<>();
public Wizard() {
}
public void castSpell(Runnable runnable) {
runnable.run();
undoStack.offerLast(runnable);
}
public void undoLastSpell() {
if (!undoStack.isEmpty()) {
var previousSpell = undoStack.pollLast();
redoStack.offerLast(previousSpell);
previousSpell.run();
}
}
public void redoLastSpell() {
if (!redoStack.isEmpty()) {
var previousSpell = redoStack.pollLast();
undoStack.offerLast(previousSpell);
previousSpell.run();
}
}
@Override
public String toString() {
return "Wizard";
}
}
@Slf4j
public abstract class Target {
private Size size;
private Visibility visibility;
public Size getSize() {
return size;
}
public void setSize(Size size) {
this.size = size;
}
public Visibility getVisibility() {
return visibility;
}
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
@Override
public abstract String toString();
public void printStatus() {
LOGGER.info("{}, [size={}] [visibility={}]", this, getSize(), getVisibility());
}
}
public class Goblin extends Target {
public Goblin() {
setSize(Size.NORMAL);
setVisibility(Visibility.VISIBLE);
}
@Override
public String toString() {
return "Goblin";
}
public void changeSize() {
var oldSize = getSize() == Size.NORMAL ? Size.SMALL : Size.NORMAL;
setSize(oldSize);
}
public void changeVisibility() {
var visible = getVisibility() == Visibility.INVISIBLE
? Visibility.VISIBLE : Visibility.INVISIBLE;
setVisibility(visible);
}
}
public static void main(String[]args){
var wizard=new Wizard();
var goblin=new Goblin();
// casts shrink/unshrink spell
wizard.castSpell(goblin::changeSize);
// casts visible/invisible spell
wizard.castSpell(goblin::changeVisibility);
// undo and redo casts
wizard.undoLastSpell();
wizard.redoLastSpell();
var wizard=new Wizard();
var goblin=new Goblin();
goblin.printStatus();
wizard.castSpell(goblin::changeSize);
goblin.printStatus();
wizard.castSpell(goblin::changeVisibility);
goblin.printStatus();
wizard.undoLastSpell();
goblin.printStatus();
wizard.undoLastSpell();
goblin.printStatus();
wizard.redoLastSpell();
goblin.printStatus();
wizard.redoLastSpell();
goblin.printStatus();
Goblin,[size=normal][visibility=visible]
Goblin,[size=small][visibility=visible]
Goblin,[size=small][visibility=invisible]
Goblin,[size=small][visibility=visible]
Goblin,[size=normal][visibility=visible]
Goblin,[size=small][visibility=visible]
Goblin,[size=small][visibility=invisible]
استخدم نمط الأمر (Command) في الحالات التالية:
- لتحديد كائنات باستخدام إجراء لتنفيذه. يمكنك التعبير عن هذه التحديدات باستخدام لغة إجراء مع دالة رد اتصال، أي دالة يتم تسجيلها في مكان ما ليتم استدعاؤها في وقت لاحق. الأوامر هي بديل موجه للكائنات لردود الاتصال.
- لتحديد، وضع في طابور وتنفيذ الطلبات في أوقات مختلفة. يمكن أن يكون لكائن الأمر حياة مستقلة عن الطلب الأصلي. إذا كان يمكن تمثيل مستلم الطلب بطريقة مستقلة عن مساحة العناوين، فيمكنك نقل كائن الأمر للطلب إلى عملية مختلفة وتنفيذ الطلب هناك.
- دعم الإلغاء. يمكن لعملية تنفيذ الأمر تخزين الحالة لإلغاء تأثيراتها في نفس الأمر. يجب أن تحتوي واجهة الأمر على عملية إضافية لإلغاء التنفيذ التي تعيد تأثيرات استدعاء سابق لتنفيذ. يتم تخزين الأوامر التي تم تنفيذها في قائمة تاريخ. يمكن تحقيق وظيفة التراجع وإعادة التنفيذ بشكل غير محدود من خلال استعراض هذه القائمة للأمام والخلف عن طريق استدعاء إلغاء التنفيذ والتنفيذ، على التوالي.
- دعم تسجيل التغييرات بحيث يمكن تطبيقها مرة أخرى في حال حدوث عطل في النظام. من خلال إضافة عمليات تحميل وتخزين إلى واجهة الأوامر، يمكنك الاحتفاظ بسجل مستمر للتغييرات. يتطلب استعادة العطل إعادة تحميل الأوامر المسجلة من القرص وتنفيذها مرة أخرى باستخدام عملية التنفيذ.
- هيكلة النظام حول عمليات عالية المستوى مبنية على عمليات بدائية. هذه الهيكلة شائعة في أنظمة المعلومات التي تدعم المعاملات. المعاملة تحتوي على مجموعة من التغييرات في البيانات. يوفر نمط الأمر طريقة لنمذجة المعاملات. تحتوي الأوامر على واجهة مشتركة تسمح باستدعاء جميع المعاملات بنفس الطريقة. كما يسهل النمط توسيع النظام مع معاملات جديدة.
- الحفاظ على سجل من الطلبات.
- تنفيذ وظيفة رد الاتصال.
- تنفيذ وظيفة التراجع.
- الأزرار في واجهة المستخدم الرسومية وعناصر القائمة في تطبيقات سطح المكتب.
- العمليات في أنظمة قواعد البيانات والأنظمة المعاملاتية التي تدعم التراجع (rollback).
- تسجيل الماكرو في التطبيقات مثل محرري النصوص وجداول البيانات.
- java.lang.Runnable
- org.junit.runners.model.Statement
- Netflix Hystrix
- javax.swing.Action
المزايا:
- يفصل الكائن الذي يستدعي العملية عن الكائن الذي يعرف كيفية تنفيذها.
- من السهل إضافة أوامر جديدة، لأنه لا يتعين عليك تغيير الفئات الموجودة.
- يمكنك تجميع مجموعة من الأوامر في أمر مركب.
العيوب:
- يزيد عدد الفئات لكل أمر فردي.
- قد يعقد التصميم عند إضافة طبقات متعددة بين المرسلين والمستلمين.