mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-14 04:58:33 +00:00
translation: Translate selected patterns to persian (#3256)
* Persian Translation: Add persian translation to abstract-document * Persian Translation: Add abstract-document.png to abstract-document folder * Persian Translation: Add codes to README.md of abstract-document * Persian Translation: some improvements in abstract-document * Persian Translation: Add refrence links in abstract-document * Persian Translation: add rtl tag in abstract-document * active-object : translate * active-object: improve when to use * active-object: improve when to use * active-object: improve bullets (test) * active-object: improve bullets (test) * active-object: improve bullets (test) * active-object: improve bullets (test) * active-object: improve bullets * active-object: Fix all bullets * -added persian translation of factory pattern * -renamed file * -changed wikipedia definition * -fixed table problem * -fixed problems in bullet alignments * Update README.md -fixed alignment in bullets * Update README.md -changed tags to English --------- Co-authored-by: Seyyed Keivan Shirkoubian <keivan.shir.74@gmail.com>
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
---
|
||||
title: "الگوی Abstract Document در جاوا: سادهسازی مدیریت داده با انعطافپذیری"
|
||||
shortTitle: Abstract Document
|
||||
description: "الگوی طراحی Abstract Document در جاوا را بررسی کنید. با هدف، توضیح، کاربرد، مزایا و نمونههای دنیای واقعی برای پیادهسازی ساختارهای دادهای پویا و انعطافپذیر آشنا شوید."
|
||||
category: Structural
|
||||
language: fa
|
||||
tag:
|
||||
- Abstraction
|
||||
- Decoupling
|
||||
- Dynamic typing
|
||||
- Encapsulation
|
||||
- Extensibility
|
||||
- Polymorphism
|
||||
---
|
||||
|
||||
## هدف الگوی طراحی Abstract Document
|
||||
|
||||
الگوی طراحی Abstract Document در جاوا یک الگوی طراحی ساختاری مهم است که راهی یکپارچه برای مدیریت ساختارهای دادهای سلسلهمراتبی و درختی فراهم میکند، با تعریف یک واسط مشترک برای انواع مختلف اسناد. این الگو ساختار اصلی سند را از فرمتهای خاص داده جدا میکند، که باعث بهروزرسانی پویا و نگهداری سادهتر میشود.
|
||||
|
||||
## توضیح دقیق الگوی Abstract Document با نمونههای دنیای واقعی
|
||||
|
||||
الگوی طراحی Abstract Document در جاوا امکان مدیریت پویا ویژگیهای پویا(غیر استاتیک) را فراهم میکند. این الگو از مفهوم traits استفاده میکند تا ایمنی نوعداده (type safety) را فراهم کرده و ویژگیهای کلاسهای مختلف را به مجموعهای از واسطها تفکیک کند.
|
||||
|
||||
مثال دنیای واقعی
|
||||
|
||||
> فرض کنید یک سیستم کتابخانه از الگوی Abstract Document در جاوا استفاده میکند، جایی که کتابها میتوانند فرمتها و ویژگیهای متنوعی داشته باشند: کتابهای فیزیکی، کتابهای الکترونیکی، و کتابهای صوتی. هر فرمت ویژگیهای خاص خود را دارد، مانند تعداد صفحات برای کتابهای فیزیکی، حجم فایل برای کتابهای الکترونیکی، و مدتزمان برای کتابهای صوتی. الگوی Abstract Document به سیستم کتابخانه اجازه میدهد تا این فرمتهای متنوع را بهصورت انعطافپذیر مدیریت کند. با استفاده از این الگو، سیستم میتواند ویژگیها را بهصورت پویا ذخیره و بازیابی کند، بدون نیاز به ساختار سفت و سخت برای هر نوع کتاب، و این کار افزودن فرمتها یا ویژگیهای جدید را در آینده بدون تغییرات عمده در کد آسان میسازد.
|
||||
|
||||
به زبان ساده
|
||||
|
||||
> الگوی Abstract Document اجازه میدهد ویژگیهایی به اشیاء متصل شوند بدون اینکه خود آن اشیاء از آن اطلاع داشته باشند.
|
||||
|
||||
ویکیپدیا میگوید
|
||||
|
||||
> یک الگوی طراحی ساختاری شیءگرا برای سازماندهی اشیاء در کلید-مقدارهایی با تایپ آزاد و ارائه دادهها از طریق نمای تایپ است. هدف این الگو دستیابی به انعطافپذیری بالا بین اجزا در یک زبان strongly typed است که در آن بتوان ویژگیهای جدیدی را بهصورت پویا به ساختار درختی اشیاء اضافه کرد، بدون از دست دادن پشتیبانی از type safety. این الگو از traits برای جداسازی ویژگیهای مختلف یک کلاس در اینترفیسهای متفاوت استفاده میکند.
|
||||
|
||||
نمودار کلاس
|
||||
|
||||

|
||||
|
||||
## مثال برنامهنویسی از الگوی Abstract Document در جاوا
|
||||
|
||||
فرض کنید یک خودرو داریم که از قطعات مختلفی تشکیل شده است. اما نمیدانیم آیا این خودرو خاص واقعاً همه قطعات را دارد یا فقط برخی از آنها. خودروهای ما پویا و بسیار انعطافپذیر هستند.
|
||||
|
||||
بیایید ابتدا کلاسهای پایه `Document` و `AbstractDocument` را تعریف کنیم. این کلاسها اساساً یک شیء را قادر میسازند تا یک نقشه از ویژگیها و هر تعداد شیء فرزند را نگه دارد.
|
||||
|
||||
```java
|
||||
public interface Document {
|
||||
|
||||
Void put(String key, Object value);
|
||||
|
||||
Object get(String key);
|
||||
|
||||
<T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor);
|
||||
}
|
||||
|
||||
public abstract class AbstractDocument implements Document {
|
||||
|
||||
private final Map<String, Object> properties;
|
||||
|
||||
protected AbstractDocument(Map<String, Object> properties) {
|
||||
Objects.requireNonNull(properties, "properties map is required");
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void put(String key, Object value) {
|
||||
properties.put(key, value);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(String key) {
|
||||
return properties.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor) {
|
||||
return Stream.ofNullable(get(key))
|
||||
.filter(Objects::nonNull)
|
||||
.map(el -> (List<Map<String, Object>>) el)
|
||||
.findAny()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.map(constructor);
|
||||
}
|
||||
|
||||
// Other properties and methods...
|
||||
}
|
||||
```
|
||||
در ادامه، یک enum به نام Property و مجموعهای از واسطها برای type، price، model و parts تعریف میکنیم. این کار به ما اجازه میدهد یک واسط با ظاهر استاتیک برای کلاس Car ایجاد کنیم.
|
||||
```java
|
||||
public enum Property {
|
||||
|
||||
PARTS, TYPE, PRICE, MODEL
|
||||
}
|
||||
|
||||
public interface HasType extends Document {
|
||||
|
||||
default Optional<String> getType() {
|
||||
return Optional.ofNullable((String) get(Property.TYPE.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public interface HasPrice extends Document {
|
||||
|
||||
default Optional<Number> getPrice() {
|
||||
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public interface HasModel extends Document {
|
||||
|
||||
default Optional<String> getModel() {
|
||||
return Optional.ofNullable((String) get(Property.MODEL.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public interface HasParts extends Document {
|
||||
|
||||
default Stream<Part> getParts() {
|
||||
return children(Property.PARTS.toString(), Part::new);
|
||||
}
|
||||
}
|
||||
|
||||
public class Part extends AbstractDocument implements HasType, HasModel, HasPrice {
|
||||
|
||||
public Part(Map<String, Object> properties) {
|
||||
super(properties);
|
||||
}
|
||||
}
|
||||
```
|
||||
اکنون آمادهایم تا کلاس Car را معرفی کنیم.
|
||||
```java
|
||||
public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
|
||||
|
||||
public Car(Map<String, Object> properties) {
|
||||
super(properties);
|
||||
}
|
||||
}
|
||||
```
|
||||
و در نهایت، نحوه ساخت و استفاده از Car را در یک مثال کامل میبینید.
|
||||
```java
|
||||
public static void main(String[] args) {
|
||||
LOGGER.info("Constructing parts and car");
|
||||
|
||||
var wheelProperties = Map.of(
|
||||
Property.TYPE.toString(), "wheel",
|
||||
Property.MODEL.toString(), "15C",
|
||||
Property.PRICE.toString(), 100L);
|
||||
|
||||
var doorProperties = Map.of(
|
||||
Property.TYPE.toString(), "door",
|
||||
Property.MODEL.toString(), "Lambo",
|
||||
Property.PRICE.toString(), 300L);
|
||||
|
||||
var carProperties = Map.of(
|
||||
Property.MODEL.toString(), "300SL",
|
||||
Property.PRICE.toString(), 10000L,
|
||||
Property.PARTS.toString(), List.of(wheelProperties, doorProperties));
|
||||
|
||||
var car = new Car(carProperties);
|
||||
|
||||
LOGGER.info("Here is our car:");
|
||||
LOGGER.info("-> model: {}", car.getModel().orElseThrow());
|
||||
LOGGER.info("-> price: {}", car.getPrice().orElseThrow());
|
||||
LOGGER.info("-> parts: ");
|
||||
car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}",
|
||||
p.getType().orElse(null),
|
||||
p.getModel().orElse(null),
|
||||
p.getPrice().orElse(null))
|
||||
);
|
||||
}
|
||||
```
|
||||
خروجی برنامه:
|
||||
```
|
||||
07:21:57.391 [main] INFO com.iluwatar.abstractdocument.App -- Constructing parts and car
|
||||
07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- Here is our car:
|
||||
07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- -> model: 300SL
|
||||
07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> price: 10000
|
||||
07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> parts:
|
||||
07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- wheel/15C/100
|
||||
07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- door/Lambo/300
|
||||
```
|
||||
|
||||
### چه زمانی از الگوی Abstract Document در جاوا استفاده کنیم؟
|
||||
|
||||
الگوی طراحی Abstract Document بهویژه در سناریوهایی مفید است که نیاز به مدیریت انواع مختلفی از اسناد در جاوا وجود دارد که برخی ویژگیها یا رفتارهای مشترک دارند، ولی ویژگیها یا رفتارهای خاص خود را نیز دارند. در ادامه چند سناریوی مناسب برای این الگو آورده شده است:
|
||||
|
||||
* سیستمهای مدیریت محتوا (CMS): ممکن است انواع مختلفی از محتوا مانند مقاله، تصویر، ویدئو و... وجود داشته باشد. هر نوع محتوا ویژگیهای مشترکی مثل تاریخ ایجاد، نویسنده و تگها دارد، ولی همچنین ویژگیهای خاصی مثل ابعاد تصویر یا مدتزمان ویدئو.
|
||||
|
||||
* سیستمهای فایل: اگر یک سیستم فایل طراحی میکنید که باید انواع مختلف فایل مانند اسناد، تصاویر، فایلهای صوتی و دایرکتوریها را مدیریت کند، این الگو میتواند راهی یکپارچه برای دسترسی به ویژگیهایی مانند اندازه فایل یا تاریخ ایجاد، فراهم کند و در عین حال ویژگیهای خاص هر نوع فایل را هم مدیریت کند.
|
||||
|
||||
* سیستمهای تجارت الکترونیک: یک پلتفرم فروش آنلاین ممکن است محصولات مختلفی داشته باشد مثل محصولات فیزیکی، فایلهای دیجیتال، و اشتراکها. این محصولات ویژگیهایی مثل نام، قیمت و توضیح را به اشتراک میگذارند، ولی ویژگیهای خاصی هم دارند مانند وزن حمل برای محصولات فیزیکی یا لینک دانلود برای دیجیتالها.
|
||||
|
||||
* سیستمهای سوابق پزشکی: در مراقبت سلامت، پرونده بیماران ممکن است دادههای مختلفی مثل مشخصات فردی، سوابق پزشکی، نتایج آزمایشها و نسخهها را شامل شود. این الگو میتواند ویژگیهای مشترک مثل شماره بیمار یا تاریخ تولد را مدیریت کند و همزمان ویژگیهای خاصی مثل نتایج آزمایش یا داروهای تجویزی را هم پوشش دهد.
|
||||
|
||||
* مدیریت پیکربندی: هنگام کار با تنظیمات پیکربندی نرمافزار، ممکن است انواع مختلفی از عناصر پیکربندی وجود داشته باشد، هر یک با ویژگیهای خاص خود. این الگو میتواند برای مدیریت این عناصر مفید باشد.
|
||||
|
||||
* پلتفرمهای آموزشی: سیستمهای آموزشی ممکن است انواع مختلفی از منابع یادگیری داشته باشند مثل محتوای متنی، ویدیوها، آزمونها و تمرینها. ویژگیهای مشترکی مثل عنوان، نویسنده و تاریخ انتشار وجود دارد، ولی ویژگیهای خاصی مانند مدت ویدیو یا مهلت تحویل تمرین نیز ممکن است وجود داشته باشد.
|
||||
|
||||
* ابزارهای مدیریت پروژه: در برنامههای مدیریت پروژه، ممکن است انواع مختلفی از وظایف مانند آیتمهای to-do، milestoneها و issueها داشته باشید. این الگو میتواند برای مدیریت ویژگیهای عمومی مانند نام وظیفه و مسئول آن استفاده شود و در عین حال ویژگیهای خاص مانند تاریخ milestone یا اولویت issue را نیز پوشش دهد.
|
||||
|
||||
* اسناد ساختار ویژگیهای متنوع و در حال تحول دارند.
|
||||
|
||||
* افزودن ویژگیهای جدید بهصورت پویا یک نیاز رایج است.
|
||||
|
||||
* جداسازی دسترسی به داده از فرمتهای خاص حیاتی است.
|
||||
|
||||
* نگهداریپذیری و انعطافپذیری برای کد اهمیت دارد.
|
||||
|
||||
ایده اصلی پشت الگوی Abstract Document فراهم کردن روشی انعطافپذیر و قابل توسعه برای مدیریت انواع مختلف اسناد یا موجودیتها با ویژگیهای مشترک و خاص است. با تعریف یک واسط مشترک و پیادهسازی آن در انواع مختلف اسناد، میتوان به شیوهای منظم و یکپارچه برای مدیریت ساختارهای پیچیده داده دست یافت.
|
||||
### مزایا و معایب الگوی Abstract Document
|
||||
<div dir="rtl">
|
||||
مزایا:
|
||||
|
||||
* انعطافپذیری: پشتیبانی از ساختارهای متنوع اسناد و ویژگیها.
|
||||
|
||||
* قابلیت توسعه: افزودن ویژگیهای جدید بدون شکستن کد موجود.
|
||||
|
||||
* نگهداریپذیری: ارتقاء کد تمیز و قابل تطبیق بهواسطه جداسازی وظایف.
|
||||
|
||||
* قابلیت استفاده مجدد: نمای دید تایپشده باعث استفاده مجدد از کد برای دسترسی به نوع خاصی از ویژگی میشود.
|
||||
|
||||
معایب:
|
||||
|
||||
* پیچیدگی: نیاز به تعریف واسطها و نماها، که باعث اضافه شدن سربار پیادهسازی میشود.
|
||||
|
||||
* کارایی: ممکن است سربار کمی نسبت به دسترسی مستقیم به داده داشته باشد.
|
||||
</div>
|
||||
|
||||
منابع و اعتبارها
|
||||
|
||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
|
||||
|
||||
* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525)
|
||||
|
||||
* [Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing (v. 4)] (https://amzn.to/49zRP4R)
|
||||
|
||||
* [Patterns of Enterprise Application Architecture] (https://amzn.to/3WfKBPR)
|
||||
|
||||
* [Abstract Document Pattern (Wikipedia)] (https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
|
||||
|
||||
* [Dealing with Properties (Martin Fowler)] (http://martinfowler.com/apsupp/properties.pdf)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
@@ -0,0 +1,220 @@
|
||||
---
|
||||
title: "الگوی Active Object در جاوا: دستیابی به پردازش ناهمگام کارآمد"
|
||||
shortTitle: Active Object
|
||||
description: "با الگوی طراحی Active Object در جاوا آشنا شوید. این راهنما رفتار ناهمگام، همزمانی (concurrency) و مثالهای کاربردی برای بهبود عملکرد برنامههای جاوای شما را پوشش میدهد."
|
||||
category: Concurrency
|
||||
language: fa
|
||||
tag:
|
||||
- Asynchronous
|
||||
- Decoupling
|
||||
- Messaging
|
||||
- Synchronization
|
||||
- Thread management
|
||||
---
|
||||
|
||||
## هدف الگوی طراحی Active Object
|
||||
|
||||
الگوی Active Object روشی مطمئن برای پردازش ناهمگام در جاوا فراهم میکند که به پاسخگو بودن برنامهها و مدیریت مؤثر threadها کمک میکند. این الگو با محصور کردن وظایف در شیءهایی که هر کدام thread و صف پیام مخصوص خود را دارند، به این هدف میرسد. این جداسازی باعث میشود thread اصلی پاسخگو باقی بماند و مشکلاتی مانند دستکاری مستقیم threadها یا دسترسی به وضعیت مشترک (shared state) به وجود نیاید.
|
||||
|
||||
## توضیح کامل الگوی Active Object با مثالهای دنیای واقعی
|
||||
|
||||
مثال دنیای واقعی
|
||||
|
||||
> تصور کنید در یک رستوران شلوغ، مشتریان سفارش خود را به گارسونها میسپارند. بهجای آنکه گارسونها خودشان به آشپزخانه بروند و غذا را آماده کنند، سفارشها را روی کاغذهایی مینویسند و به یک هماهنگکننده میدهند. این هماهنگکننده گروهی از سرآشپزها را مدیریت میکند که غذاها را به صورت ناهمگام آماده میکنند. هرگاه آشپزی آزاد شود، سفارش بعدی را از صف برمیدارد، غذا را آماده میکند و پس از آن گارسون را برای سرو غذا مطلع میسازد.
|
||||
>
|
||||
> در این قیاس، گارسونها نماینده threadهای کلاینت هستند، هماهنگکننده نقش زمانبند (scheduler) را ایفا میکند، و آشپزها نمایانگر اجرای متدها در threadهای جداگانه هستند. این ساختار باعث میشود گارسونها بتوانند بدون مسدود شدن توسط فرایند آمادهسازی غذا، سفارشهای بیشتری دریافت کنند—درست مانند اینکه الگوی Active Object، فراخوانی متد را از اجرای آن جدا میکند تا همزمانی (concurrency) را افزایش دهد.
|
||||
|
||||
به زبان ساده
|
||||
|
||||
> الگوی Active Object، اجرای متد را از فراخوانی آن جدا میکند تا در برنامههای چندریسمانی (multithreaded)، همزمانی و پاسخگویی بهتری فراهم شود.
|
||||
|
||||
طبق تعریف ویکیپدیا
|
||||
|
||||
> الگوی طراحی Active Object اجرای متد را از فراخوانی آن جدا میکند، برای شیءهایی که هرکدام thread کنترل مخصوص به خود را دارند. هدف، معرفی همزمانی با استفاده از فراخوانی متد بهصورت ناهمگام و یک زمانبند برای مدیریت درخواستها است.
|
||||
>
|
||||
> این الگو شامل شش جزء کلیدی است:
|
||||
>
|
||||
> * یک proxy، که رابطی برای کلاینتها با متدهای عمومی فراهم میکند.
|
||||
> * یک interface که درخواست متد برای شیء فعال (active object) را تعریف میکند.
|
||||
> * فهرستی از درخواستهای معلق از سوی کلاینتها.
|
||||
> * یک زمانبند (scheduler) که تصمیم میگیرد کدام درخواست بعدی اجرا شود.
|
||||
> * پیادهسازی متد شیء فعال.
|
||||
> * یک callback یا متغیر برای اینکه کلاینت نتیجه را دریافت کند.
|
||||
|
||||
نمودار توالی
|
||||
|
||||

|
||||
|
||||
## مثال برنامهنویسی از Active Object در جاوا
|
||||
|
||||
این بخش نحوه عملکرد الگوی Active Object در جاوا را توضیح میدهد و کاربرد آن در مدیریت وظایف ناهمگام و کنترل همزمانی را نشان میدهد.
|
||||
|
||||
اورکها به دلیل ذات وحشی و غیرقابل مهارشان شناخته میشوند. بهنظر میرسد هرکدام thread کنترل مخصوص خود را دارند. برای پیادهسازی یک موجود که دارای سازوکار thread مستقل خود باشد و فقط API را در اختیار قرار دهد نه اجرای داخلی را، میتوان از الگوی Active Object استفاده کرد.
|
||||
|
||||
```java
|
||||
public abstract class ActiveCreature {
|
||||
private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName());
|
||||
|
||||
private BlockingQueue<Runnable> requests;
|
||||
|
||||
private String name;
|
||||
|
||||
private Thread thread;
|
||||
|
||||
public ActiveCreature(String name) {
|
||||
this.name = name;
|
||||
this.requests = new LinkedBlockingQueue<Runnable>();
|
||||
thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
requests.take().run();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void eat() throws InterruptedException {
|
||||
requests.put(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
logger.info("{} is eating!", name());
|
||||
logger.info("{} has finished eating!", name());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void roam() throws InterruptedException {
|
||||
requests.put(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
logger.info("{} has started to roam the wastelands.", name());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
میتوان دید هر کلاسی که از ActiveCreature ارثبری کند، دارای thread کنترل مختص به خود برای فراخوانی و اجرای متدها خواهد بود.
|
||||
|
||||
برای مثال، کلاس Orc:
|
||||
|
||||
```java
|
||||
public class Orc extends ActiveCreature {
|
||||
|
||||
public Orc(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
```
|
||||
اکنون میتوان چند موجود مانند orc ایجاد کرد، به آنها دستور داد که بخورند و پرسه بزنند، و آنها این دستورات را در thread مختص به خود اجرا میکنند:
|
||||
|
||||
```java
|
||||
public class App implements Runnable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(App.class.getName());
|
||||
|
||||
private static final int NUM_CREATURES = 3;
|
||||
|
||||
public static void main(String[] args) {
|
||||
var app = new App();
|
||||
app.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
List<ActiveCreature> creatures = new ArrayList<>();
|
||||
try {
|
||||
for (int i = 0; i < NUM_CREATURES; i++) {
|
||||
creatures.add(new Orc(Orc.class.getSimpleName() + i));
|
||||
creatures.get(i).eat();
|
||||
creatures.get(i).roam();
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage());
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
for (int i = 0; i < NUM_CREATURES; i++) {
|
||||
creatures.get(i).kill(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
خروجی برنامه:
|
||||
|
||||
```
|
||||
09:00:02.501 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 is eating!
|
||||
09:00:02.501 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 is eating!
|
||||
09:00:02.501 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 is eating!
|
||||
09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has finished eating!
|
||||
09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has finished eating!
|
||||
09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has started to roam in the wastelands.
|
||||
09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has finished eating!
|
||||
09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has started to roam in the wastelands.
|
||||
09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has started to roam in the wastelands.
|
||||
```
|
||||
|
||||
چه زمانی از الگوی Active Object در جاوا استفاده کنیم؟
|
||||
|
||||
از الگوی Active Object در جاوا استفاده کنید زمانی که:
|
||||
> * نیاز دارید وظایف ناهمگام را بدون مسدود کردن thread اصلی مدیریت کنید تا عملکرد و پاسخگویی بهتری داشته باشید.
|
||||
> * نیاز به تعامل ناهمگام با منابع خارجی دارید.
|
||||
> * میخواهید پاسخگویی برنامه را افزایش دهید.
|
||||
> * نیاز به مدیریت وظایف همزمان بهصورت ماژولار و قابل نگهداری دارید.
|
||||
|
||||
آموزشهای Java برای الگوی Active Object
|
||||
> [Android and Java Concurrency: The Active Object Pattern (Douglas Schmidt)]((https://www.youtube.com/watch?v=Cd8t2u5Qmvc))
|
||||
|
||||
کاربردهای دنیای واقعی الگوی Active Object در جاوا
|
||||
|
||||
> سیستمهای معاملات بلادرنگ که درخواستها بهصورت ناهمگام پردازش میشوند.
|
||||
> که در آن وظایف طولانی در پسزمینه اجرا میشوند بدون آنکه رابط کاربری را متوقف کنند.
|
||||
> رابطهای کاربری گرافیکی (GUI)
|
||||
> برنامهنویسی بازیها برای مدیریت بهروزرسانیهای همزمان وضعیت بازی یا محاسبات هوش مصنوعی.
|
||||
|
||||
مزایا و ملاحظات الگوی Active Object
|
||||
|
||||
با مزایا و معایب استفاده از الگوی Active Object در جاوا آشنا شوید؛ از جمله بهبود ایمنی threadها و ملاحظات سربار احتمالی (overhead).
|
||||
|
||||
> مزایا:
|
||||
>
|
||||
> * پاسخگویی بهتر thread اصلی.
|
||||
> * محصورسازی مسائل مربوط به همزمانی درون شیءها.
|
||||
> * بهبود سازماندهی کد و قابلیت نگهداری.
|
||||
> * فراهمسازی ایمنی در برابر شرایط بحرانی (thread safety) و جلوگیری از مشکلات وضعیت مشترک.
|
||||
|
||||
> معایب:
|
||||
>
|
||||
> * سربار اضافی به دلیل ارسال پیام و مدیریت threadها.
|
||||
> * برای تمام سناریوهای همزمانی مناسب نیست.
|
||||
|
||||
الگوهای طراحی مرتبط در جاوا
|
||||
|
||||
> * [Command](https://java-design-patterns.com/patterns/command/): درخواست را بهعنوان یک شیء کپسوله میکند، مشابه روشی که Active Object فراخوانی متد را کپسوله میکند.
|
||||
> * [Promise](https://java-design-patterns.com/patterns/promise/): راهی برای دریافت نتیجه یک فراخوانی متد ناهمگام فراهم میکند؛ اغلب همراه با Active Object استفاده میشود.
|
||||
> * [Proxy](https://java-design-patterns.com/patterns/proxy/): الگوی Active Object میتواند از proxy برای مدیریت فراخوانیهای متد بهصورت ناهمگام استفاده کند.
|
||||
|
||||
منابع و مراجع
|
||||
|
||||
> * [Design Patterns: Elements of Reusable Object Software](https://amzn.to/3HYqrBE)
|
||||
> * [Concurrent Programming in Java: Design Principles and Patterns](https://amzn.to/498SRVq)
|
||||
> * [Java Concurrency in Practice](https://amzn.to/4aRMruW)
|
||||
> * [Learning Concurrent Programming in Scala](https://amzn.to/3UE07nV)
|
||||
> * [Pattern Languages of Program Design 3](https://amzn.to/3OI1j61)
|
||||
> * [Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects](https://amzn.to/3UgC24V)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,25 @@
|
||||
@startuml
|
||||
package com.iluwatar.activeobject {
|
||||
abstract class ActiveCreature {
|
||||
- logger : Logger
|
||||
- name : String
|
||||
- requests : BlockingQueue<Runnable>
|
||||
- thread : Thread
|
||||
+ ActiveCreature(name : String)
|
||||
+ eat()
|
||||
+ name() : String
|
||||
+ roam()
|
||||
}
|
||||
class App {
|
||||
- creatures : Integer
|
||||
- logger : Logger
|
||||
+ App()
|
||||
+ main(args : String[]) {static}
|
||||
+ run()
|
||||
}
|
||||
class Orc {
|
||||
+ Orc(name : String)
|
||||
}
|
||||
}
|
||||
Orc --|> ActiveCreature
|
||||
@enduml
|
||||
@@ -0,0 +1,155 @@
|
||||
---
|
||||
title: "الگوی factory در جاوا: سادهسازی ایجاد اشیاء"
|
||||
shortTitle: factory
|
||||
description: "الگوی طراحی factory در جاوا را با مثالها و توضیحات دقیق بیاموزید. یاد بگیرید چگونه با استفاده از الگوی factory کدی انعطافپذیر و مقیاسپذیر ایجاد کنید. مناسب برای توسعهدهندگانی که به دنبال بهبود مهارتهای طراحی شیءگرا هستند."
|
||||
category: structural
|
||||
language: fa
|
||||
tag:
|
||||
- Abstraction
|
||||
- Encapsulation
|
||||
- Gang of Four
|
||||
- Instantiation
|
||||
- Polymorphism
|
||||
---
|
||||
|
||||
## هدف از الگوی طراحی factory
|
||||
|
||||
الگوی طراحی factory در جاوا یک الگوی ساختاری است که یک رابط برای ایجاد یک شیء تعریف میکند اما به زیرکلاسها اجازه میدهد نوع اشیائی را که ایجاد خواهند شد تغییر دهند. این الگو انعطافپذیری و مقیاسپذیری را در کد شما ترویج میدهد.
|
||||
|
||||
## توضیح دقیق الگوی factory با مثالهای دنیای واقعی
|
||||
|
||||
### مثال دنیای واقعی
|
||||
|
||||
> تصور کنید در یک نانوایی انواع مختلف کیکها با استفاده از الگوی طراحی factory ساخته میشوند. `CakeFactory` فرآیند ایجاد را مدیریت میکند و امکان افزودن آسان انواع جدید کیکها را بدون تغییر در فرآیند اصلی فراهم میکند. `CakeFactory` میتواند انواع مختلفی از کیکها مانند کیک شکلاتی، کیک وانیلی و کیک توتفرنگی تولید کند. به جای اینکه کارکنان نانوایی به صورت دستی مواد اولیه را انتخاب کنند و دستورالعملهای خاصی را برای هر نوع کیک دنبال کنند، از `CakeFactory` برای مدیریت فرآیند استفاده میکنند. مشتری فقط نوع کیک را درخواست میکند و `CakeFactory` مواد اولیه و دستورالعمل مناسب را تعیین کرده و نوع خاصی از کیک را ایجاد میکند. این تنظیم به نانوایی اجازه میدهد تا انواع جدید کیکها را به راحتی اضافه کند بدون اینکه فرآیند اصلی تغییر کند، که این امر انعطافپذیری و مقیاسپذیری را ترویج میدهد.
|
||||
|
||||
### تعریف ویکیپدیا
|
||||
|
||||
> الگوی factory یک شیء برای ایجاد اشیاء دیگر است – به طور رسمی، factory یک تابع یا متدی است که اشیاء با نمونهها یا کلاسهای مختلف را بازمیگرداند.
|
||||
|
||||
### نمودار توالی
|
||||
|
||||

|
||||
|
||||
## مثال برنامهنویسی از الگوی factory در جاوا
|
||||
|
||||
تصور کنید یک کیمیاگر قصد دارد سکههایی تولید کند. کیمیاگر باید بتواند هم سکههای طلا و هم سکههای مسی ایجاد کند و تغییر بین آنها باید بدون تغییر در کد موجود امکانپذیر باشد. الگوی factory این امکان را فراهم میکند با ارائه یک متد ایجاد استاتیک که میتوان آن را با پارامترهای مرتبط فراخوانی کرد.
|
||||
|
||||
در جاوا، میتوانید الگوی factory را با تعریف یک رابط `Coin` و پیادهسازیهای آن `GoldCoin` و `CopperCoin` پیادهسازی کنید. کلاس `CoinFactory` یک متد استاتیک `getCoin` ارائه میدهد تا اشیاء سکه را بر اساس نوع ایجاد کند.
|
||||
|
||||
```java
|
||||
public interface Coin {
|
||||
String getDescription();
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
public class GoldCoin implements Coin {
|
||||
|
||||
static final String DESCRIPTION = "This is a gold coin.";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
public class CopperCoin implements Coin {
|
||||
|
||||
static final String DESCRIPTION = "This is a copper coin.";
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
کد زیر انواع سکههایی که پشتیبانی میشوند (`GoldCoin` و `CopperCoin`) را نشان میدهد.
|
||||
|
||||
```java
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum CoinType {
|
||||
|
||||
COPPER(CopperCoin::new),
|
||||
GOLD(GoldCoin::new);
|
||||
|
||||
private final Supplier<Coin> constructor;
|
||||
}
|
||||
```
|
||||
|
||||
سپس متد استاتیک `getCoin` برای ایجاد اشیاء سکه در کلاس factory `CoinFactory` کپسوله شده است.
|
||||
|
||||
```java
|
||||
public class CoinFactory {
|
||||
|
||||
public static Coin getCoin(CoinType type) {
|
||||
return type.getConstructor().get();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
اکنون، در کد کلاینت، میتوانیم انواع مختلفی از سکهها را با استفاده از کلاس factory تولید کنیم.
|
||||
|
||||
```java
|
||||
public static void main(String[] args) {
|
||||
LOGGER.info("The alchemist begins his work.");
|
||||
var coin1 = CoinFactory.getCoin(CoinType.COPPER);
|
||||
var coin2 = CoinFactory.getCoin(CoinType.GOLD);
|
||||
LOGGER.info(coin1.getDescription());
|
||||
LOGGER.info(coin2.getDescription());
|
||||
}
|
||||
```
|
||||
|
||||
خروجی برنامه:
|
||||
|
||||
```
|
||||
06:19:53.530 [main] INFO com.iluwatar.factory.App -- The alchemist begins his work.
|
||||
06:19:53.533 [main] INFO com.iluwatar.factory.App -- This is a copper coin.
|
||||
06:19:53.533 [main] INFO com.iluwatar.factory.App -- This is a gold coin.
|
||||
```
|
||||
|
||||
## زمان استفاده از الگوی factory در جاوا
|
||||
|
||||
* از الگوی طراحی factory در جاوا زمانی استفاده کنید که کلاس از قبل نوع دقیق و وابستگیهای اشیائی که نیاز به ایجاد آن دارد را نمیداند.
|
||||
* زمانی که یک متد یکی از چندین کلاس ممکن که یک کلاس والد مشترک دارند را بازمیگرداند و میخواهد منطق انتخاب شیء را کپسوله کند.
|
||||
* این الگو معمولاً هنگام طراحی فریمورکها یا کتابخانهها برای ارائه بهترین انعطافپذیری و جداسازی از انواع کلاسهای خاص استفاده میشود.
|
||||
|
||||
## کاربردهای دنیای واقعی الگوی factory در جاوا
|
||||
|
||||
> * [java.util.Calendar#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--)
|
||||
> * [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-)
|
||||
> * [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--)
|
||||
> * [java.nio.charset.Charset#forName()](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-)
|
||||
> * این مورد [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) اشیاء singleton مختلف را بر اساس یک پروتکل بازمیگرداند
|
||||
> * [java.util.EnumSet#of()](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of(E))
|
||||
> * [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) و متدهای مشابه دیگر.
|
||||
>
|
||||
> * کتابخانهی JavaFX از الگوهای factory برای ایجاد کنترلهای مختلف رابط کاربری متناسب با نیازهای محیط کاربر استفاده میکند.
|
||||
|
||||
## مزایا و معایب الگوی factory
|
||||
|
||||
### مزایا:
|
||||
|
||||
> * پیادهسازی الگوی factory در برنامه جاوای شما، وابستگی بین پیادهسازی و کلاسهایی که استفاده میکند را کاهش میدهد.
|
||||
> * از [اصل Open/Closed](https://java-design-patterns.com/principles/#open-closed-principle) پشتیبانی میکند، زیرا سیستم میتواند انواع جدیدی را بدون تغییر کد موجود معرفی کند.
|
||||
|
||||
### معایب:
|
||||
|
||||
> * کد میتواند به دلیل معرفی چندین کلاس اضافی پیچیدهتر شود.
|
||||
> * استفاده بیش از حد میتواند کد را کمتر خوانا کند اگر پیچیدگی ایجاد اشیاء کم یا غیرضروری باشد.
|
||||
|
||||
## الگوهای طراحی مرتبط با جاوا
|
||||
|
||||
> * الگوی [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): میتوان آن را نوعی factory در نظر گرفت که با گروهی از محصولات کار میکند.
|
||||
> * الگوی [Singleton](https://java-design-patterns.com/patterns/singleton/): اغلب همراه با factory استفاده میشود تا اطمینان حاصل شود که یک کلاس تنها یک نمونه دارد.
|
||||
> * الگوی [Builder](https://java-design-patterns.com/patterns/builder/): ساخت یک شیء پیچیده را از نمایش آن جدا میکند، مشابه نحوهای که factoryها مدیریت نمونهسازی را انجام میدهند.
|
||||
> * الگوی [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/): یک factory از محتوای غیرقابل تغییر با رابطهای builder و factory جداگانه است.
|
||||
|
||||
## منابع و اعتبارات
|
||||
|
||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0Rk5y)
|
||||
* [Effective Java](https://amzn.to/4cGk2Jz)
|
||||
* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/3UpTLrG)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Reference in New Issue
Block a user