|
| 1 | +--- |
| 2 | +title: "الگوی Active Object در جاوا: دستیابی به پردازش ناهمگام کارآمد" |
| 3 | +shortTitle: Active Object |
| 4 | +description: "با الگوی طراحی Active Object در جاوا آشنا شوید. این راهنما رفتار ناهمگام، همزمانی (concurrency) و مثالهای کاربردی برای بهبود عملکرد برنامههای جاوای شما را پوشش میدهد." |
| 5 | +category: Concurrency |
| 6 | +language: fa |
| 7 | +tag: |
| 8 | + - Asynchronous |
| 9 | + - Decoupling |
| 10 | + - Messaging |
| 11 | + - Synchronization |
| 12 | + - Thread management |
| 13 | +--- |
| 14 | + |
| 15 | +## هدف الگوی طراحی Active Object |
| 16 | + |
| 17 | +الگوی Active Object روشی مطمئن برای پردازش ناهمگام در جاوا فراهم میکند که به پاسخگو بودن برنامهها و مدیریت مؤثر threadها کمک میکند. این الگو با محصور کردن وظایف در شیءهایی که هر کدام thread و صف پیام مخصوص خود را دارند، به این هدف میرسد. این جداسازی باعث میشود thread اصلی پاسخگو باقی بماند و مشکلاتی مانند دستکاری مستقیم threadها یا دسترسی به وضعیت مشترک (shared state) به وجود نیاید. |
| 18 | + |
| 19 | +## توضیح کامل الگوی Active Object با مثالهای دنیای واقعی |
| 20 | + |
| 21 | +مثال دنیای واقعی |
| 22 | + |
| 23 | +> تصور کنید در یک رستوران شلوغ، مشتریان سفارش خود را به گارسونها میسپارند. بهجای آنکه گارسونها خودشان به آشپزخانه بروند و غذا را آماده کنند، سفارشها را روی کاغذهایی مینویسند و به یک هماهنگکننده میدهند. این هماهنگکننده گروهی از سرآشپزها را مدیریت میکند که غذاها را به صورت ناهمگام آماده میکنند. هرگاه آشپزی آزاد شود، سفارش بعدی را از صف برمیدارد، غذا را آماده میکند و پس از آن گارسون را برای سرو غذا مطلع میسازد. |
| 24 | +> |
| 25 | +> در این قیاس، گارسونها نماینده threadهای کلاینت هستند، هماهنگکننده نقش زمانبند (scheduler) را ایفا میکند، و آشپزها نمایانگر اجرای متدها در threadهای جداگانه هستند. این ساختار باعث میشود گارسونها بتوانند بدون مسدود شدن توسط فرایند آمادهسازی غذا، سفارشهای بیشتری دریافت کنند—درست مانند اینکه الگوی Active Object، فراخوانی متد را از اجرای آن جدا میکند تا همزمانی (concurrency) را افزایش دهد. |
| 26 | +
|
| 27 | +به زبان ساده |
| 28 | + |
| 29 | +> الگوی Active Object، اجرای متد را از فراخوانی آن جدا میکند تا در برنامههای چندریسمانی (multithreaded)، همزمانی و پاسخگویی بهتری فراهم شود. |
| 30 | +
|
| 31 | +طبق تعریف ویکیپدیا |
| 32 | + |
| 33 | +> الگوی طراحی Active Object اجرای متد را از فراخوانی آن جدا میکند، برای شیءهایی که هرکدام thread کنترل مخصوص به خود را دارند. هدف، معرفی همزمانی با استفاده از فراخوانی متد بهصورت ناهمگام و یک زمانبند برای مدیریت درخواستها است. |
| 34 | +> |
| 35 | +> این الگو شامل شش جزء کلیدی است: |
| 36 | +> |
| 37 | +> * یک proxy، که رابطی برای کلاینتها با متدهای عمومی فراهم میکند. |
| 38 | +> * یک interface که درخواست متد برای شیء فعال (active object) را تعریف میکند. |
| 39 | +> * فهرستی از درخواستهای معلق از سوی کلاینتها. |
| 40 | +> * یک زمانبند (scheduler) که تصمیم میگیرد کدام درخواست بعدی اجرا شود. |
| 41 | +> * پیادهسازی متد شیء فعال. |
| 42 | +> * یک callback یا متغیر برای اینکه کلاینت نتیجه را دریافت کند. |
| 43 | +
|
| 44 | +نمودار توالی |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | +## مثال برنامهنویسی از Active Object در جاوا |
| 49 | + |
| 50 | +این بخش نحوه عملکرد الگوی Active Object در جاوا را توضیح میدهد و کاربرد آن در مدیریت وظایف ناهمگام و کنترل همزمانی را نشان میدهد. |
| 51 | + |
| 52 | +اورکها به دلیل ذات وحشی و غیرقابل مهارشان شناخته میشوند. بهنظر میرسد هرکدام thread کنترل مخصوص خود را دارند. برای پیادهسازی یک موجود که دارای سازوکار thread مستقل خود باشد و فقط API را در اختیار قرار دهد نه اجرای داخلی را، میتوان از الگوی Active Object استفاده کرد. |
| 53 | + |
| 54 | +```java |
| 55 | +public abstract class ActiveCreature { |
| 56 | + private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName()); |
| 57 | + |
| 58 | + private BlockingQueue<Runnable> requests; |
| 59 | + |
| 60 | + private String name; |
| 61 | + |
| 62 | + private Thread thread; |
| 63 | + |
| 64 | + public ActiveCreature(String name) { |
| 65 | + this.name = name; |
| 66 | + this.requests = new LinkedBlockingQueue<Runnable>(); |
| 67 | + thread = new Thread(new Runnable() { |
| 68 | + @Override |
| 69 | + public void run() { |
| 70 | + while (true) { |
| 71 | + try { |
| 72 | + requests.take().run(); |
| 73 | + } catch (InterruptedException e) { |
| 74 | + logger.error(e.getMessage()); |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + } |
| 79 | + ); |
| 80 | + thread.start(); |
| 81 | + } |
| 82 | + |
| 83 | + public void eat() throws InterruptedException { |
| 84 | + requests.put(new Runnable() { |
| 85 | + @Override |
| 86 | + public void run() { |
| 87 | + logger.info("{} is eating!", name()); |
| 88 | + logger.info("{} has finished eating!", name()); |
| 89 | + } |
| 90 | + } |
| 91 | + ); |
| 92 | + } |
| 93 | + |
| 94 | + public void roam() throws InterruptedException { |
| 95 | + requests.put(new Runnable() { |
| 96 | + @Override |
| 97 | + public void run() { |
| 98 | + logger.info("{} has started to roam the wastelands.", name()); |
| 99 | + } |
| 100 | + } |
| 101 | + ); |
| 102 | + } |
| 103 | + |
| 104 | + public String name() { |
| 105 | + return this.name; |
| 106 | + } |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +میتوان دید هر کلاسی که از ActiveCreature ارثبری کند، دارای thread کنترل مختص به خود برای فراخوانی و اجرای متدها خواهد بود. |
| 111 | + |
| 112 | +برای مثال، کلاس Orc: |
| 113 | + |
| 114 | +```java |
| 115 | +public class Orc extends ActiveCreature { |
| 116 | + |
| 117 | + public Orc(String name) { |
| 118 | + super(name); |
| 119 | + } |
| 120 | +} |
| 121 | +``` |
| 122 | +اکنون میتوان چند موجود مانند orc ایجاد کرد، به آنها دستور داد که بخورند و پرسه بزنند، و آنها این دستورات را در thread مختص به خود اجرا میکنند: |
| 123 | + |
| 124 | +```java |
| 125 | +public class App implements Runnable { |
| 126 | + |
| 127 | + private static final Logger logger = LoggerFactory.getLogger(App.class.getName()); |
| 128 | + |
| 129 | + private static final int NUM_CREATURES = 3; |
| 130 | + |
| 131 | + public static void main(String[] args) { |
| 132 | + var app = new App(); |
| 133 | + app.run(); |
| 134 | + } |
| 135 | + |
| 136 | + @Override |
| 137 | + public void run() { |
| 138 | + List<ActiveCreature> creatures = new ArrayList<>(); |
| 139 | + try { |
| 140 | + for (int i = 0; i < NUM_CREATURES; i++) { |
| 141 | + creatures.add(new Orc(Orc.class.getSimpleName() + i)); |
| 142 | + creatures.get(i).eat(); |
| 143 | + creatures.get(i).roam(); |
| 144 | + } |
| 145 | + Thread.sleep(1000); |
| 146 | + } catch (InterruptedException e) { |
| 147 | + logger.error(e.getMessage()); |
| 148 | + Thread.currentThread().interrupt(); |
| 149 | + } finally { |
| 150 | + for (int i = 0; i < NUM_CREATURES; i++) { |
| 151 | + creatures.get(i).kill(0); |
| 152 | + } |
| 153 | + } |
| 154 | + } |
| 155 | +} |
| 156 | +``` |
| 157 | + |
| 158 | +خروجی برنامه: |
| 159 | + |
| 160 | +``` |
| 161 | +09:00:02.501 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 is eating! |
| 162 | +09:00:02.501 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 is eating! |
| 163 | +09:00:02.501 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 is eating! |
| 164 | +09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has finished eating! |
| 165 | +09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has finished eating! |
| 166 | +09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has started to roam in the wastelands. |
| 167 | +09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has finished eating! |
| 168 | +09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has started to roam in the wastelands. |
| 169 | +09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has started to roam in the wastelands. |
| 170 | +``` |
| 171 | + |
| 172 | +چه زمانی از الگوی Active Object در جاوا استفاده کنیم؟ |
| 173 | + |
| 174 | +از الگوی Active Object در جاوا استفاده کنید زمانی که: |
| 175 | +> * نیاز دارید وظایف ناهمگام را بدون مسدود کردن thread اصلی مدیریت کنید تا عملکرد و پاسخگویی بهتری داشته باشید. |
| 176 | +> * نیاز به تعامل ناهمگام با منابع خارجی دارید. |
| 177 | +> * میخواهید پاسخگویی برنامه را افزایش دهید. |
| 178 | +> * نیاز به مدیریت وظایف همزمان بهصورت ماژولار و قابل نگهداری دارید. |
| 179 | +
|
| 180 | +آموزشهای Java برای الگوی Active Object |
| 181 | +> [Android and Java Concurrency: The Active Object Pattern (Douglas Schmidt)]((https://www.youtube.com/watch?v=Cd8t2u5Qmvc)) |
| 182 | +
|
| 183 | +کاربردهای دنیای واقعی الگوی Active Object در جاوا |
| 184 | + |
| 185 | +> سیستمهای معاملات بلادرنگ که درخواستها بهصورت ناهمگام پردازش میشوند. |
| 186 | +> که در آن وظایف طولانی در پسزمینه اجرا میشوند بدون آنکه رابط کاربری را متوقف کنند. |
| 187 | +> رابطهای کاربری گرافیکی (GUI) |
| 188 | +> برنامهنویسی بازیها برای مدیریت بهروزرسانیهای همزمان وضعیت بازی یا محاسبات هوش مصنوعی. |
| 189 | +
|
| 190 | +مزایا و ملاحظات الگوی Active Object |
| 191 | + |
| 192 | +با مزایا و معایب استفاده از الگوی Active Object در جاوا آشنا شوید؛ از جمله بهبود ایمنی threadها و ملاحظات سربار احتمالی (overhead). |
| 193 | + |
| 194 | +> مزایا: |
| 195 | +> |
| 196 | +> * پاسخگویی بهتر thread اصلی. |
| 197 | +> * محصورسازی مسائل مربوط به همزمانی درون شیءها. |
| 198 | +> * بهبود سازماندهی کد و قابلیت نگهداری. |
| 199 | +> * فراهمسازی ایمنی در برابر شرایط بحرانی (thread safety) و جلوگیری از مشکلات وضعیت مشترک. |
| 200 | +
|
| 201 | +> معایب: |
| 202 | +> |
| 203 | +> * سربار اضافی به دلیل ارسال پیام و مدیریت threadها. |
| 204 | +> * برای تمام سناریوهای همزمانی مناسب نیست. |
| 205 | +
|
| 206 | +الگوهای طراحی مرتبط در جاوا |
| 207 | + |
| 208 | +> * [Command](https://java-design-patterns.com/patterns/command/): درخواست را بهعنوان یک شیء کپسوله میکند، مشابه روشی که Active Object فراخوانی متد را کپسوله میکند. |
| 209 | +> * [Promise](https://java-design-patterns.com/patterns/promise/): راهی برای دریافت نتیجه یک فراخوانی متد ناهمگام فراهم میکند؛ اغلب همراه با Active Object استفاده میشود. |
| 210 | +> * [Proxy](https://java-design-patterns.com/patterns/proxy/): الگوی Active Object میتواند از proxy برای مدیریت فراخوانیهای متد بهصورت ناهمگام استفاده کند. |
| 211 | +
|
| 212 | +منابع و مراجع |
| 213 | + |
| 214 | +> * [Design Patterns: Elements of Reusable Object Software](https://amzn.to/3HYqrBE) |
| 215 | +> * [Concurrent Programming in Java: Design Principles and Patterns](https://amzn.to/498SRVq) |
| 216 | +> * [Java Concurrency in Practice](https://amzn.to/4aRMruW) |
| 217 | +> * [Learning Concurrent Programming in Scala](https://amzn.to/3UE07nV) |
| 218 | +> * [Pattern Languages of Program Design 3](https://amzn.to/3OI1j61) |
| 219 | +> * [Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects](https://amzn.to/3UgC24V) |
| 220 | +
|
0 commit comments