diff --git a/localization/ar/abstract-document/README.md b/localization/ar/abstract-document/README.md new file mode 100644 index 000000000000..bf1599124f26 --- /dev/null +++ b/localization/ar/abstract-document/README.md @@ -0,0 +1,188 @@ +--- +title: Abstract Document +shortTitle: Abstract Document +category: Structural +language: ar +tag: + - Extensibility +--- + + +## الهدف + +استخدام الخصائص الديناميكية والحصول على مرونة اللغات غير المتغيرة مع الحفاظ على أمان الأنواع. + +## التوضيح + +يتيح استخدام نمط الوثيقة المجردة إدارة الخصائص غير الثابتة الإضافية. يستخدم هذا النمط مفهوم +السمات لتمكين أمان الأنواع وخصائص مفصولة من فئات مختلفة في مجموعة من الواجهات. + +مثال من العالم الحقيقي + +> خذ على سبيل المثال سيارة مكونة من العديد من الأجزاء. ومع ذلك، لا نعرف إذا كانت السيارة تحتوي على جميع الأجزاء أو جزء منها فقط. سياراتنا ديناميكية ومرنة للغاية. + +بصيغة أخرى + +> يسمح نمط الوثيقة المجردة بإضافة خصائص إلى الكائنات دون أن تكون هذه الكائنات على دراية بذلك. + +حسب ويكيبيديا + +> نمط تصميم هيكلي موجه للكائنات لتنظيم الكائنات في حاويات من نوع مفتاح-قيمة بشكل فضفاض مع نوعية غير محددة، وكشف البيانات باستخدام طرق عرض مهيكلة. الهدف من هذا النمط هو تحقيق درجة عالية من المرونة بين المكونات في لغة قوية النوع حيث يمكن إضافة خصائص جديدة إلى شجرة الكائنات أثناء العمل دون فقدان دعم أمان الأنواع. يستخدم النمط السمات لفصل خصائص مختلفة للفئة إلى واجهات متعددة. + +**مثال برمجي** + +أولاً، دعونا نعرف الفئات الأساسية `Document` و `AbstractDocument`. في الأساس، تجعل الكائن يحتوي على خريطة من الخصائص وأي عدد من الكائنات الفرعية. + + +```java +public interface Document { + + Void put(String key, Object value); + + Object get(String key); + + Stream children(String key, Function, T> constructor); +} + +public abstract class AbstractDocument implements Document { + + private final Map properties; + + protected AbstractDocument(Map 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 Stream children(String key, Function, T> constructor) { + return Stream.ofNullable(get(key)) + .filter(Objects::nonNull) + .map(el -> (List>) el) + .findAny() + .stream() + .flatMap(Collection::stream) + .map(constructor); + } + ... +} +``` + +بعد ذلك، نعرف `enum` لـ `Property` ومجموعة من الواجهات للنمط، السعر، النموذج، والأجزاء. هذا يتيح لنا إنشاء واجهات تظهر بشكل ثابت لفئة `Car`. + + +```java +public enum Property { + + PARTS, TYPE, PRICE, MODEL +} + +public interface HasType extends Document { + + default Optional getType() { + return Optional.ofNullable((String) get(Property.TYPE.toString())); + } +} + +public interface HasPrice extends Document { + + default Optional getPrice() { + return Optional.ofNullable((Number) get(Property.PRICE.toString())); + } +} +public interface HasModel extends Document { + + default Optional getModel() { + return Optional.ofNullable((String) get(Property.MODEL.toString())); + } +} + +public interface HasParts extends Document { + + default Stream getParts() { + return children(Property.PARTS.toString(), Part::new); + } +} +``` + +Ahora estamos listos para introducir el Coche `Car`. + +```java +public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts { + + public Car(Map properties) { + super(properties); + } +} +``` + +وأخيرًا، هكذا نبني ونستخدم السيارة `Car` في مثال كامل. + + +```java + 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)) + ); + + // Constructing parts and car + // Here is our car: + // model: 300SL + // price: 10000 + // parts: + // wheel/15C/100 + // door/Lambo/300 +``` + +## Diagrama de clases + +![alt text](./etc/abstract-document.png "Abstract Document Traits and Domain") + +## التطبيق + +استخدم نمط الوثيقة المجردة عندما: + +* يوجد حاجة لإضافة خصائص أثناء العمل. +* ترغب في طريقة مرنة لتنظيم النطاق في هيكل مشابه لشجرة. +* ترغب في نظام أقل ترابطًا. + +## الحقوق + + +* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern) +* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf) +* [Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing (v. 4)](https://www.amazon.com/gp/product/0470059028/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0470059028&linkId=e3aacaea7017258acf184f9f3283b492) \ No newline at end of file diff --git a/localization/ar/abstract-document/etc/abstract-document.png b/localization/ar/abstract-document/etc/abstract-document.png new file mode 100644 index 000000000000..6bc0b29a4e77 Binary files /dev/null and b/localization/ar/abstract-document/etc/abstract-document.png differ diff --git a/localization/ar/abstract-factory/README.md b/localization/ar/abstract-factory/README.md new file mode 100644 index 000000000000..230c9ae12b44 --- /dev/null +++ b/localization/ar/abstract-factory/README.md @@ -0,0 +1,234 @@ +--- +title: Abstract Factory +shortTitle: Abstract Factory +category: Creational +language: ar +tag: + - Gang of Four +--- +## يُعرف أيضًا باسم + +Kit + +## الهدف + +توفير واجهة لإنشاء عائلات من الكائنات المرتبطة المعتمدة دون تحديد فئتها المحددة. + +## التوضيح + +مثال من العالم الحقيقي + +> لإنشاء مملكة نحتاج إلى كائنات بموضوع مشترك. المملكة الإلفية تحتاج إلى ملك إلفي، وقلعة إلفية، وجيش إلفي، بينما المملكة الأوركية تحتاج إلى ملك أوركي، وقلعة أوركية، وجيش أوركي. هناك اعتماد بين كائنات المملكة. + +بصيغة أخرى + +> مصنع للمصانع؛ مصنع يجمع بين مصانع فردية ولكنها مرتبطة/معتمدة دون تحديد فئتها المحددة. + +حسب ويكيبيديا + +> يوفر نمط المصنع المجرد طريقة لتغليف مجموعة من المصانع الفردية التي لها موضوع مشترك دون تحديد فئاتها المحددة. + +**مثال برمجي** + +ترجمة المثال السابق حول الممالك. أولاً لدينا بعض الواجهات والتنفيذات لكائنات `Castle`. + + +```java +public interface Castle { + String getDescription(); +} + +public interface King { + String getDescription(); +} + +public interface Army { + String getDescription(); +} + +// Elven implementations -> +public class ElfCastle implements Castle { + static final String DESCRIPTION = "This is the elven castle!"; + @Override + public String getDescription() { + return DESCRIPTION; + } +} +public class ElfKing implements King { + static final String DESCRIPTION = "This is the elven king!"; + @Override + public String getDescription() { + return DESCRIPTION; + } +} +public class ElfArmy implements Army { + static final String DESCRIPTION = "This is the elven Army!"; + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +// التنفيذات Orcish بطريقة مشابهة +-> ... + +``` + +ثم لدينا التجريد والتنفيذ لمصنع المملكة `KingdomFactory`. + + +```java +public interface KingdomFactory { + Castle createCastle(); + King createKing(); + Army createArmy(); +} + +public class ElfKingdomFactory implements KingdomFactory { + + @Override + public Castle createCastle() { + return new ElfCastle(); + } + + @Override + public King createKing() { + return new ElfKing(); + } + + @Override + public Army createArmy() { + return new ElfArmy(); + } +} + +public class OrcKingdomFactory implements KingdomFactory { + + @Override + public Castle createCastle() { + return new OrcCastle(); + } + + @Override + public King createKing() { + return new OrcKing(); + } + + @Override + public Army createArmy() { + return new OrcArmy(); + } +} +``` + +الآن لدينا المصنع المجرد الذي يسمح لنا بإنشاء عائلات من الكائنات المرتبطة. على سبيل المثال، مصنع المملكة الإلفية `ElfKingdomFactory` يقوم بإنشاء القلعة `castle`، الملك `king`، والجيش `army`، إلخ. + + + +```java +var factory = new ElfKingdomFactory(); +var castle = factory.createCastle(); +var king = factory.createKing(); +var army = factory.createArmy(); + +castle.getDescription(); +king.getDescription(); +army.getDescription(); +``` + +ناتج البرنامج: + + +```java +This is the elven castle! +This is the elven king! +This is the elven Army! +``` + +الآن يمكننا تصميم مصنع لمصانع الممالك الخاصة بنا. في هذا المثال، قمنا بإنشاء `FactoryMaker`، المسؤول عن إعادة نسخة من `ElfKingdomFactory` أو `OrcKingdomFactory`. +يمكن للعميل استخدام `FactoryMaker` لإنشاء مصنع محدد، والذي بدوره سينتج كائنات محددة مختلفة (مشتقة من `Army` و `King` و `Castle`). +في هذا المثال نستخدم أيضًا `enum` لتمرير نوع مصنع المملكة الذي سيطلبه العميل. + + +```java +public static class FactoryMaker { + + public enum KingdomType { + ELF, ORC + } + + public static KingdomFactory makeFactory(KingdomType type) { + return switch (type) { + case ELF -> new ElfKingdomFactory(); + case ORC -> new OrcKingdomFactory(); + default -> throw new IllegalArgumentException("KingdomType not supported."); + }; + } +} + + public static void main(String[] args) { + var app = new App(); + + LOGGER.info("Elf Kingdom"); + app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF)); + LOGGER.info(app.getArmy().getDescription()); + LOGGER.info(app.getCastle().getDescription()); + LOGGER.info(app.getKing().getDescription()); + + LOGGER.info("Orc Kingdom"); + app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC)); + --similar use of the orc factory + } +``` + +## مخطط الفئات + +![alt text](./etc/abstract-factory.urm.png "Diagrama de Clases de Abstract Factory") + + +## التطبيق + +استخدم نمط المصنع المجرد عندما: + +* يجب أن يكون النظام غير متحيز حول كيفية إنشاء وتركيب وتمثيل كائناته. +* يجب تكوين النظام مع إحدى عائلات المنتجات المتعددة. +* تم تصميم عائلة الكائنات المرتبطة لتستخدم معًا وتحتاج إلى فرض هذا الافتراض. +* ترغب في توفير مكتبة من المنتجات ولا تريد الكشف عن تنفيذاتها، بل واجهاتها فقط. +* العمر الافتراضي للاعتماد هو مفهومًا أقصر من عمر العميل. +* تحتاج إلى قيمة في وقت التشغيل لبناء الاعتماد. +* تريد تحديد أي منتج من العائلة يتم استدعاؤه في وقت التشغيل. +* تحتاج إلى توفير واحد أو أكثر من المعلمات المعروفة فقط في وقت التشغيل قبل أن تتمكن من حل الاعتماد. +* تحتاج إلى الاتساق بين المنتجات. +* لا تريد تغيير الكود الموجود عند إضافة منتجات أو عائلات جديدة من المنتجات إلى البرنامج. + +أمثلة على حالات الاستخدام + +* اختيار استدعاء التنفيذ الصحيح لـ FileSystemAcmeService أو DatabaseAcmeService أو NetworkAcmeService في وقت التشغيل. +* كتابة الاختبارات الوحدوية تصبح أسهل بكثير. +* أدوات واجهة المستخدم (UI) لأنظمة تشغيل مختلفة (SO). + +## العواقب + +* إخفاء حقن الاعتمادات في جافا داخل كائنات الخدمة قد يؤدي إلى أخطاء في وقت التشغيل كان يمكن تجنبها في وقت الترجمة. +* بينما يكون النمط جيدًا في إنشاء كائنات محددة مسبقًا، قد يكون من الصعب إضافة الجديدة. +* الكود يصبح أكثر تعقيدًا مما ينبغي لأنه يتم إضافة العديد من الواجهات والفئات الجديدة جنبًا إلى جنب مع النمط. + +## الدروس التعليمية + +* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java) + +## الاستخدامات المعروفة + +* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) +* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--) +* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--) + +## الأنماط المتعلقة + +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/) +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) + +## الحقوق + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) diff --git a/localization/ar/abstract-factory/etc/abstract-factory.urm.png b/localization/ar/abstract-factory/etc/abstract-factory.urm.png new file mode 100644 index 000000000000..836858a2c652 Binary files /dev/null and b/localization/ar/abstract-factory/etc/abstract-factory.urm.png differ diff --git a/localization/ar/active-object/README.md b/localization/ar/active-object/README.md new file mode 100644 index 000000000000..842570a2604a --- /dev/null +++ b/localization/ar/active-object/README.md @@ -0,0 +1,126 @@ +--- +title: Active Object +shortTitle: Active Object +category: Concurrency +language: ar +tag: + - Performance +--- + + +## الهدف +يفصل نمط التصميم الكائن النشط بين تنفيذ الطريقة واستدعائها للكائنات التي تعمل في خيط تحكم خاص بها. الهدف هو إدخال التزامن باستخدام استدعاءات الطرق غير المتزامنة وجدولة لإدارة الطلبات. + +## التوضيح + +ستحتوي الفئة التي تنفذ نمط التصميم الكائن النشط على آلية مزامنة ذاتية دون استخدام الطرق المتزامنة (synchronized). + +مثال من العالم الحقيقي + +> الأورك معروفون بوحشيتهم وفلسفتهم في عدم العمل الجماعي. بناءً على هذا السلوك، يمكن القول إن لديهم خيط تحكم خاص بهم. + +يمكننا استخدام نمط الكائن النشط لتنفيذ مخلوق لديه خيط تحكم خاص به ويعرض واجهة برمجة التطبيقات (API) الخاصة به، ولكن ليس التنفيذ نفسه. + +**مثال برمجي** + + +```java +public abstract class ActiveCreature{ + private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName()); + + private BlockingQueue requests; + + private String name; + + private Thread thread; + + public ActiveCreature(String name) { + this.name = name; + this.requests = new LinkedBlockingQueue(); + 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 سيكون لديها خيط تحكم خاص بها لاستدعاء وتنفيذ الطرق. + +على سبيل المثال، الفئة Orc: + +```java +public class Orc extends ActiveCreature { + + public Orc(String name) { + super(name); + } + +} +``` +الآن يمكننا إنشاء مخلوقات متعددة مثل الأورك، نطلب منهم الأكل والتجول، وسيفعلون ذلك في خيط التحكم الخاص بهم: + +```java + public static void main(String[] args) { + var app = new App(); + app.run(); + } + + @Override + public void run() { + ActiveCreature creature; + try { + for (int i = 0;i < creatures;i++) { + creature = new Orc(Orc.class.getSimpleName().toString() + i); + creature.eat(); + creature.roam(); + } + Thread.sleep(1000); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + Runtime.getRuntime().exit(1); + } +``` + +## مخطط الفئات + +![alt text](./etc/active-object.urm.png "Active Object class diagram") + +## الدروس التعليمية + +* [Android and Java Concurrency: The Active Object Pattern](https://www.youtube.com/watch?v=Cd8t2u5Qmvc) \ No newline at end of file diff --git a/localization/ar/active-object/etc/active-object.urm.png b/localization/ar/active-object/etc/active-object.urm.png new file mode 100644 index 000000000000..c14f66144ee2 Binary files /dev/null and b/localization/ar/active-object/etc/active-object.urm.png differ diff --git a/localization/ar/acyclic-visitor/README.md b/localization/ar/acyclic-visitor/README.md new file mode 100644 index 000000000000..8bb8e01a154f --- /dev/null +++ b/localization/ar/acyclic-visitor/README.md @@ -0,0 +1,167 @@ +--- +title: Acyclic Visitor +shortTitle: Acyclic Visitor +category: Behavioral +language: ar +tag: + - Extensibility +--- +## الهدف + +السماح بإضافة وظائف جديدة إلى تسلسلات الفئات الموجودة دون التأثير عليها، ودون إنشاء الدوائر المعتمدة المزعجة التي هي جزء من نمط GoF (Gang of Four) للزائر (Visitor). + +## التوضيح + +مثال من العالم الحقيقي + +> لدينا تسلسل فئات مودم. يجب أن تتم زيارة المودمات في هذه التسلسلات بواسطة خوارزمية خارجية بناءً على بعض الفلاتر (هل المودم متوافق مع Unix أو DOS؟). + +بصيغة أخرى + +> يتيح نمط Acyclic Visitor إضافة وظائف إلى تسلسلات الفئات الموجودة دون تعديلها. + +[WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) يقول + +> يسمح نمط Acyclic Visitor بإضافة وظائف جديدة إلى تسلسلات الفئات الموجودة دون التأثير عليها، ودون إنشاء الدوائر المعتمدة التي هي جزء من نمط الزائر (Visitor Pattern) في GangOfFour. + +**مثال برمجي** + +هنا لدينا تسلسل `Modem`. + + +```java +public abstract class Modem { + public abstract void accept(ModemVisitor modemVisitor); +} + +public class Zoom extends Modem { + ... + @Override + public void accept(ModemVisitor modemVisitor) { + if (modemVisitor instanceof ZoomVisitor) { + ((ZoomVisitor) modemVisitor).visit(this); + } else { + LOGGER.info("Only ZoomVisitor is allowed to visit Zoom modem"); + } + } +} + +public class Hayes extends Modem { + ... + @Override + public void accept(ModemVisitor modemVisitor) { + if (modemVisitor instanceof HayesVisitor) { + ((HayesVisitor) modemVisitor).visit(this); + } else { + LOGGER.info("Only HayesVisitor is allowed to visit Hayes modem"); + } + } +} +``` + +بعد ذلك، لدينا تسلسل `ModemVisitor`. + + +```java +public interface ModemVisitor { +} + +public interface HayesVisitor extends ModemVisitor { + void visit(Hayes hayes); +} + +public interface ZoomVisitor extends ModemVisitor { + void visit(Zoom zoom); +} + +public interface AllModemVisitor extends ZoomVisitor, HayesVisitor { +} + +public class ConfigureForDosVisitor implements AllModemVisitor { + ... + @Override + public void visit(Hayes hayes) { + LOGGER.info(hayes + " used with Dos configurator."); + } + @Override + public void visit(Zoom zoom) { + LOGGER.info(zoom + " used with Dos configurator."); + } +} + +public class ConfigureForUnixVisitor implements ZoomVisitor { + ... + @Override + public void visit(Zoom zoom) { + LOGGER.info(zoom + " used with Unix configurator."); + } +} +``` + +وأخيرًا، هنا "الزوار" في العمل. + + +```java + var conUnix = new ConfigureForUnixVisitor(); + var conDos = new ConfigureForDosVisitor(); + var zoom = new Zoom(); + var hayes = new Hayes(); + hayes.accept(conDos); + zoom.accept(conDos); + hayes.accept(conUnix); + zoom.accept(conUnix); +``` + +ناتج البرنامج: + + +``` + // Hayes modem used with Dos configurator. + // Zoom modem used with Dos configurator. + // Only HayesVisitor is allowed to visit Hayes modem + // Zoom modem used with Unix configurator. +``` + + +## مخطط الفئات + +![alt text](./etc/acyclic-visitor.png "Acyclic Visitor") + +## التطبيق + +يمكن استخدام هذا النمط في الحالات التالية: + +* عندما تحتاج إلى إضافة وظيفة جديدة إلى تسلسل فئات دون التأثير عليها أو تعديلها. +* عندما توجد وظائف تعمل على التسلسل ولكنها لا تنتمي إلى التسلسل بحد ذاته. على سبيل المثال، الفئات `ConfigureForDOS` و `ConfigureForUnix` و `ConfigureForX`. +* عندما تحتاج إلى تنفيذ عمليات مختلفة تمامًا على كائن اعتمادًا على نوعه. +* عندما يكون من المتوقع توسيع التسلسل الزائر بشكل متكرر باستخدام مشتقات من فئة العنصر. +* عندما يكون عملية إعادة التجميع، الربط، الاختبار أو توزيع المشتقات من فئة العنصر مرهقة جدًا. + +## الدروس التعليمية + +* [Acyclic Visitor Pattern Example](https://codecrafter.blogspot.com/2012/12/the-acyclic-visitor-pattern.html) + +## العواقب + +الجوانب الجيدة: + +* لا توجد دوائر اعتماد بين التسلسلات. +* لا حاجة لإعادة تجميع جميع الزوار إذا تم إضافة زائر جديد. +* لا يسبب أخطاء في الترجمة في الزوار الموجودين إذا كانت التسلسل تحتوي على عضو جديد. + +الجوانب السيئة: + + +* ينتهك [مبدأ الاستبدال في ليسكوف](https://java-design-patterns.com/principles/#liskov-substitution-principle) من خلال إظهار أنه يمكن قبول جميع الزوار مع الاهتمام بزائر واحد فقط. +* يجب إنشاء تسلسل زوار موازٍ لجميع الأعضاء في التسلسل الذي يمكن زيارته. + +## الأنماط المتعلقة + +* [Visitor Pattern](https://java-design-patterns.com/patterns/visitor/) + + +## الحقوق + + +* [Acyclic Visitor by Robert C. Martin](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf) +* [Acyclic Visitor in WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) diff --git a/localization/ar/acyclic-visitor/etc/acyclic-visitor.png b/localization/ar/acyclic-visitor/etc/acyclic-visitor.png new file mode 100644 index 000000000000..7b4df13d80f8 Binary files /dev/null and b/localization/ar/acyclic-visitor/etc/acyclic-visitor.png differ diff --git a/localization/ar/adapter/README.md b/localization/ar/adapter/README.md new file mode 100644 index 000000000000..06cb0a14ae6e --- /dev/null +++ b/localization/ar/adapter/README.md @@ -0,0 +1,141 @@ +--- +title: Adapter +shortTitle: Adapter +category: Structural +language: ar +tag: + - Gang of Four +--- + +## أيضًا معروف بـ +الغطاء (Wrapper) + +## الهدف +تحويل واجهة فئة إلى واجهة أخرى يتوقعها العميل. يتيح نمط المحول (Adapter) للفئات العمل مع فئات أخرى التي لا يمكنها العمل معها في الظروف العادية بسبب مشاكل التوافق. + +## التوضيح + +مثال من العالم الحقيقي + +> تخيل أنك تمتلك بعض الصور في بطاقة ذاكرة وتريد نقلها إلى جهاز الكمبيوتر الخاص بك. لنقل الصور، تحتاج إلى نوع من المحول الذي يتوافق مع منافذ جهاز الكمبيوتر الخاص بك ويسمح لك بإدخال البطاقة. في هذه الحالة، قارئ البطاقات هو محول (Adapter). +> مثال آخر هو محول التيار الكهربائي؛ إذا كان هناك قابس بثلاثة دبابيس ولا يمكن توصيله بمنفذ كهربائي به ثقبين، فإنه يحتاج إلى محول لجعله متوافقًا مع المنفذ. +> مثال آخر هو مترجم يترجم كلمات من شخص لآخر. + +بصيغة أخرى + +> يتيح نمط المحول (Adapter) تغليف كائن داخل محول لجعله متوافقًا مع فئة سيكون غير متوافق معها بطريقة أخرى. + +حسب ويكيبيديا + +> في هندسة البرمجيات، نمط المحول هو نمط تصميم برمجي يسمح باستخدام واجهة فئة موجودة كواجهة مختلفة. وغالبًا ما يُستخدم لجعل الفئات الموجودة تعمل مع فئات أخرى دون الحاجة إلى تعديل كود المصدر الخاص بها. + +**مثال برمجي** + +خذ على سبيل المثال قبطان يمكنه فقط استخدام القوارب التي تعمل بالمجاديف ولا يمكنه الإبحار على الإطلاق. + +أولاً، لدينا الواجهات `RowingBoat` (قارب المجاديف) و `FishingBoat` (قارب الصيد). + +```java +public interface RowingBoat { + void row(); +} + +@Slf4j +public class FishingBoat { + public void sail() { + LOGGER.info("The fishing boat is sailing"); + } +} +``` + +ويتوقع القبطان تنفيذ واجهة `RowingBoat` (قارب المجاديف) ليتمكن من التحرك. + + +```java +public class Captain { + + private final RowingBoat rowingBoat; + // default constructor and setter for rowingBoat + public Captain(RowingBoat rowingBoat) { + this.rowingBoat = rowingBoat; + } + + public void row() { + rowingBoat.row(); + } +} +``` + +الآن لنفترض أن مجموعة من القراصنة قد جاءت ويجب على قائدنا الهروب، ولكن هناك فقط قارب صيد. نحتاج إلى إنشاء محول يسمح للقائد باستخدام قارب الصيد مع مهاراته لاستخدام القوارب التي تعمل بالمجاديف. + + +```java +@Slf4j +public class FishingBoatAdapter implements RowingBoat { + + private final FishingBoat boat; + + public FishingBoatAdapter() { + boat = new FishingBoat(); + } + + @Override + public void row() { + boat.sail(); + } +} +``` + +والآن يمكن لـ `Captain` (القائد) استخدام `FishingBoat` (قارب الصيد) للهروب من القراصنة. + + +```java +var captain = new Captain(new FishingBoatAdapter()); +captain.row(); +``` + +## مخطط الفئات +![alt text](./etc/adapter.urm.png "Adapter class diagram") + +## التطبيق +استخدم نمط المحول (Adapter) عندما: + +* تريد استخدام فئة موجودة وواجهتها لا تتناسب مع ما تحتاجه. +* تريد إنشاء فئة قابلة لإعادة الاستخدام تتعاون مع فئات غير مرتبطة أو لم يكن من المخطط تعاونها معًا، أي فئات ليس لديها بالضرورة واجهات متوافقة. +* تحتاج إلى استخدام عدة فئات فرعية موجودة، ولكن من غير العملي تعديل واجهتها عن طريق إنشاء فئات فرعية لكل واحدة. يمكن للمحول تعديل واجهة الفئة الأصلية. +* العديد من التطبيقات التي تستخدم مكتبات طرف ثالث تستخدم المحولات كطبقات وسيطة بين التطبيق والمكتبة لفصل التطبيق عن المكتبة. إذا كان من الضروري استخدام مكتبة أخرى، يكفي إنشاء محول للمكتبة الجديدة دون الحاجة إلى تعديل كود التطبيق. + +## الدروس + + +* [Dzone](https://dzone.com/articles/adapter-design-pattern-in-java) +* [Refactoring Guru](https://refactoring.guru/design-patterns/adapter/java/example) +* [Baeldung](https://www.baeldung.com/java-adapter-pattern) + +## العواقب +المحولات بين الفئات والكائنات لها خصائص مختلفة. محول الفئات + +* يقوم بإجراء التكيف ويرتبط بفئة محددة. كنتيجة لذلك، لن يعمل محول الفئات عندما نريد تكيف فئة وفئاتها الفرعية. +* يسمح للمحول بتعديل سلوك الفئة المتكيفة لأن المحول هو فئة فرعية من الفئة المتكيفة. +* يستخدم كائنًا واحدًا ولا يحتاج إلى استخدام مؤشرات إضافية للإشارة إلى الفئة المتكيفة. + +محوّل الكائنات + +* يسمح للمحول الواحد بالعمل مع العديد من الفئات، أي مع الفئة المتكيفة وكل الفئات الفرعية لها (إذا كانت موجودة). يمكن للمحول أيضًا إضافة وظائف إلى جميع الفئات المتكيفة في نفس الوقت. +* يجعل من الصعب تعديل سلوك الفئة المتكيفة. سيكون من الضروري إنشاء فئة فرعية للفئة المتكيفة وجعل المحول يشير إلى الفئة الفرعية بدلاً من الفئة الأصلية. + +## أمثلة من العالم الواقعي + + +* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29) +* [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-) +* [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-) +* [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-) + + +## الشكر + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) diff --git a/localization/ar/adapter/etc/adapter.urm.png b/localization/ar/adapter/etc/adapter.urm.png new file mode 100644 index 000000000000..341ad67699d9 Binary files /dev/null and b/localization/ar/adapter/etc/adapter.urm.png differ diff --git a/localization/ar/aggregator-microservices/README.md b/localization/ar/aggregator-microservices/README.md new file mode 100644 index 000000000000..40d3ff26f7a8 --- /dev/null +++ b/localization/ar/aggregator-microservices/README.md @@ -0,0 +1,111 @@ +--- +title: Aggregator Microservices +shortTitle: Aggregator Microservices +category: Architectural +language: ar +tag: +- Cloud distributed +- Decoupling +- Microservices +--- + +## الهدف + +يقوم المستخدم بإجراء مكالمة واحدة إلى خدمة المجمع، ومن ثم يقوم المجمع بالاتصال بكل خدمة ميكروسيرفيس ذات صلة. + +## الشرح + +مثال من العالم الواقعي + +> يحتاج سوقنا الإلكتروني إلى معلومات حول المنتجات والمخزون الحالي. يقوم بإجراء مكالمة إلى خدمة المجمع التي بدورها تتصل بخدمة ميكروسيرفيس المعلومات الخاصة بالمنتج وخدمة ميكروسيرفيس المخزون للمنتج التي تعيد المعلومات مجمعة. + +ببساطة + +> يقوم ميكروسيرفيس المجمع بجمع البيانات من عدة ميكروسيرفيسات ويعيد النتيجة مجمعة لمعالجتها. + +يقول StackOverflow + +> يقوم ميكروسيرفيس المجمع بالاتصال بعدة خدمات لتحقيق الوظيفة المطلوبة من التطبيق. + +**مثال برمجي** + +لنبدأ بنموذج البيانات. هنا هو `Product`. + + +```java +public class Product { + private String title; + private int productInventories; + // getters and setters -> + ... +} +``` + +بعد ذلك، يمكننا تقديم ميكروسيرفيسنا `Aggregator` (مجمع الميكروسيرفيسات). يحتوي على `ProductInformationClient` (عميل معلومات المنتج) و +`ProductInventoryClient` (عميل مخزون المنتج) للاتصال بالميكروسيرفيسات المعنية. + + +```java +@RestController +public class Aggregator { + + @Resource + private ProductInformationClient informationClient; + + @Resource + private ProductInventoryClient inventoryClient; + + @RequestMapping(path = "/product", method = RequestMethod.GET) + public Product getProduct() { + + var product = new Product(); + var productTitle = informationClient.getProductTitle(); + var productInventory = inventoryClient.getProductInventories(); + + //Fallback to error message + product.setTitle(requireNonNullElse(productTitle, "Error: Fetching Product Title Failed")); + + //Fallback to default error inventory + product.setProductInventories(requireNonNullElse(productInventory, -1)); + + return product; + } +} +``` + +هذه هي جوهر تنفيذ الميكروسيرفيسات للمعلومات. ميكروسيرفيس المخزون مشابه، ببساطة يعيد +عدد المخزون. + + +```java +@RestController +public class InformationController { + @RequestMapping(value = "/information", method = RequestMethod.GET) + public String getProductTitle() { + return "The Product Title."; + } +} +``` + +الآن عند استدعاء واجهة برمجة التطبيقات REST الخاصة بنا `Aggregator` تُرجع معلومات المنتج. + + +```bash +curl http://localhost:50004/product +{"title":"The Product Title.","productInventories":5} +``` + +## مخطط الفئة + +![alt text](./aggregator-service/etc/aggregator-service.png "Aggregator Microservice") + +## قابلية التطبيق + +استخدم نمط تجميع الميكروسيرفيسات (Aggregator Microservices) عندما تحتاج إلى واجهة برمجة تطبيقات موحدة لعدة ميكروسيرفيسات، بغض النظر عن جهاز العميل. + + +## الشكر + +* [أنماط تصميم الميكروسيرفيس](http://web.archive.org/web/20190705163602/http://blog.arungupta.me/microservice-design-patterns/) +* [أنماط الميكروسيرفيس: مع أمثلة في Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=8b4e570267bc5fb8b8189917b461dc60) +* [أنماط العمارة: اكتشاف الأنماط الأساسية في أكثر المجالات ضرورة في العمارة المؤسسية](https://www.amazon.com/gp/product/B077T7V8RC/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B077T7V8RC&linkId=c34d204bfe1b277914b420189f09c1a4) diff --git a/localization/ar/aggregator-microservices/aggregator-service/etc/aggregator-service.png b/localization/ar/aggregator-microservices/aggregator-service/etc/aggregator-service.png new file mode 100644 index 000000000000..75ee82328bbe Binary files /dev/null and b/localization/ar/aggregator-microservices/aggregator-service/etc/aggregator-service.png differ diff --git a/localization/ar/ambassador/README.md b/localization/ar/ambassador/README.md new file mode 100644 index 000000000000..b70fe071eb31 --- /dev/null +++ b/localization/ar/ambassador/README.md @@ -0,0 +1,210 @@ +--- +title: Ambassador +shortTitle: Ambassador +category: Structural +language: ar +tag: + - Decoupling + - Cloud distributed +--- + +## الهدف + +توفير مثيل من الخدمة المساعدة للعميل وتفويض الوظائف المشتركة لها من مصدر مشترك. + +## الشرح + +مثال واقعي + +> خدمة بعيدة تحتوي على العديد من العملاء الذين يصلون إلى وظيفة تقدمها هذه الخدمة. الخدمة هي تطبيق قديم ومن +> المستحيل تحديثها. عدد كبير من الطلبات من قبل المستخدمين تسبب مشاكل في الاتصال. يجب تنفيذ قواعد جديدة +> بشأن تكرار الطلبات جنبًا إلى جنب مع فحوصات التأخير والسجلات من جانب العميل. + +بكلمات أخرى + +> باستخدام نمط Ambassador، يمكننا تنفيذ تقليل تكرار الطلبات من العملاء جنبًا إلى جنب مع فحوصات التأخير +> والسجلات. + +وفقًا لوثائق مايكروسوفت + +> يمكن اعتبار خدمة Ambassador وكأنها وكيل خارج العملية يتواجد جنبًا إلى جنب مع العميل. +> +> يمكن أن يكون هذا النمط مفيدًا لتفريغ المهام المشتركة في الاتصال من العميل مثل المراقبة، السجلات، التوجيه، +> الأمان (مثل TLS) وأنماط المقاومة (*) بطريقة مستقلة عن اللغة. غالبًا ما يُستخدم مع التطبيقات القديمة، +> أو التطبيقات الأخرى التي يصعب تعديلها، بهدف توسيع قدراتها في الشبكات. يمكنه أيضًا +> تمكين فريق متخصص لتنفيذ هذه الميزات. + +**مثال على الكود** + +مع المقدمة السابقة في الاعتبار، سنقوم بمحاكاة وظيفتها في المثال التالي. لدينا واجهة يتم تنفيذها +من قبل الخدمة البعيدة وكذلك خدمة Ambassador: + +```java +interface RemoteServiceInterface { + long doRemoteFunction(int value) throws Exception; +} +``` + +## خدمة بعيدة ممثلة كـ Singleton (مثيل واحد). + +```java +@Slf4j +public class RemoteService implements RemoteServiceInterface { + private static RemoteService service = null; + + static synchronized RemoteService getRemoteService() { + if (service == null) { + service = new RemoteService(); + } + return service; + } + + private RemoteService() {} + + @Override + public long doRemoteFunction(int value) { + long waitTime = (long) Math.floor(Math.random() * 1000); + + try { + sleep(waitTime); + } catch (InterruptedException e) { + LOGGER.error("Thread sleep interrupted", e); + } + + return waitTime >= 200 ? value * 10 : -1; + } +} +``` + +## خدمة السفير مع إضافة وظائف إضافية مثل السجلات والتحقق من الكمون + +```java +@Slf4j +public class ServiceAmbassador implements RemoteServiceInterface { + private static final int RETRIES = 3; + private static final int DELAY_MS = 3000; + + ServiceAmbassador() { + } + + @Override + public long doRemoteFunction(int value) { + return safeCall(value); + } + + private long checkLatency(int value) { + var startTime = System.currentTimeMillis(); + var result = RemoteService.getRemoteService().doRemoteFunction(value); + var timeTaken = System.currentTimeMillis() - startTime; + + LOGGER.info("Time taken (ms): " + timeTaken); + return result; + } + + private long safeCall(int value) { + var retries = 0; + var result = (long) FAILURE; + + for (int i = 0; i < RETRIES; i++) { + if (retries >= RETRIES) { + return FAILURE; + } + + if ((result = checkLatency(value)) == FAILURE) { + LOGGER.info("Failed to reach remote: (" + (i + 1) + ")"); + retries++; + try { + sleep(DELAY_MS); + } catch (InterruptedException e) { + LOGGER.error("Thread sleep state interrupted", e); + } + } else { + break; + } + } + return result; + } +} +``` + +العميل لديه خدمة سفير محلية تستخدم للتفاعل مع الخدمة البعيدة: + + +```java +@Slf4j +public class Client { + private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador(); + + long useService(int value) { + var result = serviceAmbassador.doRemoteFunction(value); + LOGGER.info("Service result: " + result); + return result; + } +} +``` + +بعد ذلك، لدينا عميلان يستخدمان الخدمة: + + +```java +public class App { + public static void main(String[] args) { + var host1 = new Client(); + var host2 = new Client(); + host1.useService(12); + host2.useService(73); + } +} +``` + +هذه هي النتيجة التي سنحصل عليها بعد تنفيذ المثال: + + +```java +Time taken (ms): 111 +Service result: 120 +Time taken (ms): 931 +Failed to reach remote: (1) +Time taken (ms): 665 +Failed to reach remote: (2) +Time taken (ms): 538 +Failed to reach remote: (3) +Service result: -1 +``` + +## مخطط الفئات + +![alt text](./etc/ambassador.urm.png "مخطط فئات Ambassador") + +## التطبيقات + +يتم تطبيق نمط Ambassador عندما نعمل مع خدمة بعيدة قديمة لا يمكن تعديلها أو أنه سيكون من الصعب للغاية تعديلها. يمكن تنفيذ خصائص الاتصال في العميل دون الحاجة إلى إجراء تغييرات على الخدمة البعيدة. + +* يوفر Ambassador واجهة محلية لخدمة بعيدة. +* يوفر Ambassador سجلات، انقطاع الدائرة، إعادة المحاولات، والأمان في العميل. + +## حالات الاستخدام النموذجية + +* التحكم في الوصول إلى كائن آخر +* تنفيذ السجلات أو السجلات +* تنفيذ انقطاع الدائرة +* تفويض مهام الخدمات البعيدة +* تسهيل الاتصال بالشبكة + +## الاستخدامات المعروفة + +* [بوابة API المدمجة مع Kubernetes للخدمات الصغيرة](https://github.com/datawire/ambassador) + +## الأنماط ذات الصلة + +* [الوكيل (Proxy)](https://java-design-patterns.com/patterns/proxy/) + +## الشكر + +* [نمط Ambassador (وثائق Microsoft باللغة الإنجليزية)](https://docs.microsoft.com/en-us/azure/architecture/patterns/ambassador) +* [تصميم الأنظمة الموزعة: الأنماط والمفاهيم للخدمات القابلة للتوسع وموثوقة](https://www.amazon.com/s?k=designing+distributed+systems&sprefix=designing+distri%2Caps%2C156&linkCode=ll2&tag=javadesignpat-20&linkId=a12581e625462f9038557b01794e5341&language=en_US&ref_=as_li_ss_tl) + +## ملاحظات المترجم +(*) تشير النسخة الأصلية بالإنجليزية من وثائق Microsoft إلى مصطلح المرونة +وفي الترجمة الإسبانية يتم ترجمته إلى المقاومة، على الرغم من ربطه بالقسم الخاص بنمط الموثوقية. انظر: +* [نسخة الوثائق الخاصة بنمط Ambassador من Microsoft باللغة الإسبانية.](https://learn.microsoft.com/es-es/azure/architecture/patterns/ambassador) diff --git a/localization/ar/ambassador/etc/ambassador.urm.png b/localization/ar/ambassador/etc/ambassador.urm.png new file mode 100644 index 000000000000..9b50a02ad356 Binary files /dev/null and b/localization/ar/ambassador/etc/ambassador.urm.png differ diff --git a/localization/ar/api-gateway/README.md b/localization/ar/api-gateway/README.md new file mode 100644 index 000000000000..a3f33a1c40eb --- /dev/null +++ b/localization/ar/api-gateway/README.md @@ -0,0 +1,170 @@ +--- +title: API Gateway +shortTitle: API Gateway +category: Architectural +language: ar +tag: + - Cloud distributed + - Decoupling + - Microservices +--- + +## الهدف + +إضافة استدعاءات إلى الخدمات الصغيرة في نفس المكان، بوابة API (API Gateway). يقوم المستخدم +بإجراء استدعاء بسيط إلى بوابة API، وتقوم بوابة API بدورها باستدعاء كل خدمة صغيرة ذات صلة. + +## الشرح + +مع نمط الخدمات الصغيرة، قد يحتاج العميل إلى بيانات من عدة خدمات صغيرة. إذا كان +العميل سيستدعي كل خدمة صغيرة بشكل مباشر، فقد يؤدي ذلك إلى أوقات تحميل طويلة، حيث +يجب على العميل إجراء طلب شبكة لكل خدمة صغيرة يتم استدعاؤها. بالإضافة إلى ذلك، وجود +استدعاء العميل لكل خدمة صغيرة يربط العميل مباشرة بتلك الخدمة الصغيرة - إذا حدث تغيير داخلي +في الخدمات الصغيرة (على سبيل المثال، إذا تم دمج خدمتين صغيرتين في وقت ما في المستقبل) أو إذا تغير الموقع (الخادم والمنفذ) لأحد الخدمات الصغيرة، فإن كل +عميل يستخدم تلك الخدمات الصغيرة يجب تحديثه. + +الهدف من نمط بوابة API هو تخفيف بعض هذه المشاكل. في نمط بوابة API، يتم وضع كيان إضافي +(بوابة API) بين العميل والخدمات الصغيرة. +مهمة بوابة API هي إضافة استدعاءات إلى الخدمات الصغيرة. بدلاً من أن يقوم العميل +بإجراء استدعاء لكل خدمة صغيرة على حدة، يقوم العميل باستدعاء بوابة API مرة واحدة فقط. ثم تقوم بوابة +API باستدعاء كل واحدة من الخدمات الصغيرة التي يحتاجها العميل. + +مثال واقعي + +> نحن نطبق نظام خدمات صغيرة وبوابة API لموقع تجارة إلكترونية. في هذا +> النظام تقوم بوابة API بإجراء استدعاءات إلى خدمات Image و Price. (الصورة والسعر) + +بمعنى آخر + +> في نظام يتم تنفيذه باستخدام بنية خدمات صغيرة، تعتبر بوابة API هي النقطة +> الوحيدة للوصول التي تجمع استدعاءات الخدمات الصغيرة الفردية. + +تقول ويكيبيديا + +> بوابة API هي خادم يعمل كواجهة أمامية لـ API، يستقبل طلبات API، ويطبق +> حدودًا وسياسات الأمان، ويرسل الطلبات إلى الخدمة الخلفية ثم يعيد +> الاستجابة إلى الطالب. غالبًا ما تشمل بوابة API محركًا للتحويل لتنظيم +> وتعديل الطلبات والاستجابات أثناء سير العملية. يمكن أن توفر بوابة +> API أيضًا وظائف مثل جمع تحليلات البيانات والتخزين المؤقت. قد +> توفر بوابة API وظائف لدعم المصادقة، والتفويض، والأمان، +> والتدقيق، والامتثال. + +**كود المثال** + +يوضح هذا التنفيذ كيف قد يبدو نمط بوابة API لموقع تجارة إلكترونية. تقوم +`ApiGateway` بإجراء استدعاءات إلى خدمات Image و Price باستخدام +`ImageClientImpl` و `PriceClientImpl` على التوالي. العملاء الذين يشاهدون الموقع +على جهاز مكتبي يمكنهم مشاهدة معلومات الأسعار وصورة المنتج، لذلك تقوم `ApiGateway` +بإجراء استدعاء إلى الخدمات الصغيرة وجمع البيانات في نموذج `DesktopProduct`. +ومع ذلك، فإن مستخدمي الأجهزة المحمولة يرون فقط معلومات الأسعار، ولا يشاهدون صورة المنتج. +بالنسبة لمستخدمي الأجهزة المحمولة، تقوم `ApiGateway` فقط +بالحصول على معلومات الأسعار، والتي تستخدم لإكمال `MobileProduct`. + +إليك تنفيذ خدمة الصورة (Image). + + +```java +public interface ImageClient { + String getImagePath(); +} + +public class ImageClientImpl implements ImageClient { + @Override + public String getImagePath() { + var httpClient = HttpClient.newHttpClient(); + var httpGet = HttpRequest.newBuilder() + .GET() + .uri(URI.create("http://localhost:50005/image-path")) + .build(); + + try { + var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString()); + return httpResponse.body(); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + + return null; + } +} +``` + +إليك تنفيذ خدمة المصغرة للسعر (Price). + +```java +public interface PriceClient { + String getPrice(); +} + +public class PriceClientImpl implements PriceClient { + + @Override + public String getPrice() { + var httpClient = HttpClient.newHttpClient(); + var httpGet = HttpRequest.newBuilder() + .GET() + .uri(URI.create("http://localhost:50006/price")) + .build(); + + try { + var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString()); + return httpResponse.body(); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + + return null; + } +} +``` + +هنا يمكننا أن نرى كيف تقوم بوابة الـ API بتوجيه الطلبات إلى الخدمات المصغرة. + +```java +public class ApiGateway { + + @Resource + private ImageClient imageClient; + + @Resource + private PriceClient priceClient; + + @RequestMapping(path = "/desktop", method = RequestMethod.GET) + public DesktopProduct getProductDesktop() { + var desktopProduct = new DesktopProduct(); + desktopProduct.setImagePath(imageClient.getImagePath()); + desktopProduct.setPrice(priceClient.getPrice()); + return desktopProduct; + } + + @RequestMapping(path = "/mobile", method = RequestMethod.GET) + public MobileProduct getProductMobile() { + var mobileProduct = new MobileProduct(); + mobileProduct.setPrice(priceClient.getPrice()); + return mobileProduct; + } +} +``` + +## مخطط الفئة + +![alt text](./etc/api-gateway.png "API Gateway") + +## التطبيقات + +استخدم نمط API Gateway عندما + +* تكون تستخدم بنية ميكروسيرفيسز وتحتاج إلى نقطة تجميع واحدة لاستدعاءات الميكروسيرفيسز. + +## الدروس التعليمية + +* [Exploring the New Spring Cloud Gateway](https://www.baeldung.com/spring-cloud-gateway) +* [Spring Cloud - Gateway](https://www.tutorialspoint.com/spring_cloud/spring_cloud_gateway.htm) +* [Getting Started With Spring Cloud Gateway](https://dzone.com/articles/getting-started-with-spring-cloud-gateway) + +## الشكر + +* [microservices.io - API Gateway](http://microservices.io/patterns/apigateway.html) +* [NGINX - Building Microservices: Using an API Gateway](https://www.nginx.com/blog/building-microservices-using-an-api-gateway/) +* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=ac7b6a57f866ac006a309d9086e8cfbd) +* [Building Microservices: Designing Fine-Grained Systems](https://www.amazon.com/gp/product/1491950358/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1491950358&linkId=4c95ca9831e05e3f0dadb08841d77bf1) diff --git a/localization/ar/api-gateway/etc/api-gateway.png b/localization/ar/api-gateway/etc/api-gateway.png new file mode 100644 index 000000000000..bb3ec2e2e1a8 Binary files /dev/null and b/localization/ar/api-gateway/etc/api-gateway.png differ diff --git a/localization/ar/arrange-act-assert/README.md b/localization/ar/arrange-act-assert/README.md new file mode 100644 index 000000000000..ed99bb686a7f --- /dev/null +++ b/localization/ar/arrange-act-assert/README.md @@ -0,0 +1,142 @@ +--- +title: Arrange/Act/Assert +shortTitle: Arrange/Act/Assert +category: Idiom +language: ar +tag: + - Testing +--- + +## أيضا معروف بـ + +Dado/Cuando/Entonces + +## الغرض + +Arrange/Act/Assert (AAA) هو نمط لتنظيم اختبارات الوحدة. +يقسم اختبارات الوحدة إلى ثلاث خطوات واضحة ومميزة: + +1. Arrange(تنظيم): قم بإعداد التهيئة والتهيئة اللازمة للاختبار. +2. Act(العمل): اتخذ التدابير اللازمة للاختبار. +3. Assert(التأكيد): تحقق من نتائج الاختبار. + +## الشرح + +لهذا النمط العديد من الفوائد الكبيرة. فهو يخلق فصلًا واضحًا بين إعدادات الاختبار، العمليات والنتائج. هذا الهيكل يجعل الكود أسهل في القراءة والفهم. إذا +وضعت الخطوات بالترتيب وصيغت الكود بطريقة تفصلها، يمكنك مسح الاختبار وفهمه بسرعة. + +كما أنه يفرض درجة معينة من الانضباط عند كتابة اختبارات الوحدة. يجب أن تكون قادرًا على تصور +بوضوح الخطوات الثلاث التي سيقوم بها اختبارك. هذا يجعل الاختبارات أكثر بديهية للكتابة مع الحفاظ على هيكل واضح. + +مثال يومي + +> نحتاج إلى كتابة مجموعة من اختبارات الوحدة كاملة وواضحة لفئة. + +بعبارة أخرى + +> Arrange/Act/Assert هو نمط اختبار ينظم الاختبارات إلى ثلاث خطوات واضحة لتسهيل +> الصيانة. + +WikiWikiWeb يقول + +> Arrange/Act/Assert هو نمط لتنظيم وتنسيق الكود في طرق اختبار الوحدة. + +**كود المثال** + +لنلقِ نظرة أولاً على فئتنا `Cash` التي سيتم اختبارها. + + +```java +public class Cash { + + private int amount; + + Cash(int amount) { + this.amount = amount; + } + + void plus(int addend) { + amount += addend; + } + + boolean minus(int subtrahend) { + if (amount >= subtrahend) { + amount -= subtrahend; + return true; + } else { + return false; + } + } + + int count() { + return amount; + } +} +``` + +ثم نكتب اختبارات الوحدة الخاصة بنا بناءً على نمط Arrange/Act/Assert. لاحظ بوضوح الفصل بين الخطوات لكل اختبار وحدة. + + +```java +class CashAAATest { + + @Test + void testPlus() { + //Arrange + var cash = new Cash(3); + //Act + cash.plus(4); + //Assert + assertEquals(7, cash.count()); + } + + @Test + void testMinus() { + //Arrange + var cash = new Cash(8); + //Act + var result = cash.minus(5); + //Assert + assertTrue(result); + assertEquals(3, cash.count()); + } + + @Test + void testInsufficientMinus() { + //Arrange + var cash = new Cash(1); + //Act + var result = cash.minus(6); + //Assert + assertFalse(result); + assertEquals(1, cash.count()); + } + + @Test + void testUpdate() { + //Arrange + var cash = new Cash(5); + //Act + cash.plus(6); + var result = cash.minus(3); + //Assert + assertTrue(result); + assertEquals(8, cash.count()); + } +} +``` + +## القابلية للتطبيق + +استخدم نمط Arrange/Act/Assert عندما + +* تحتاج إلى تنظيم اختبارات الوحدة الخاصة بك لتكون أسهل في القراءة والصيانة والتحسين. + +## الشكر + +* [Arrange, Act, Assert: ¿Qué son las pruebas AAA?](https://blog.ncrunch.net/post/arrange-act-assert-aaa-testing.aspx) +* [Bill Wake: 3A – Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/) +* [Martin Fowler: DadoCuandoEntonces](https://martinfowler.com/bliki/GivenWhenThen.html) +* [Patrones de prueba xUnit: Refactorizando Código de prueba](https://www.amazon.com/gp/product/0131495054/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0131495054&linkId=99701e8f4af2f63d0bcf50) +* [Principios, prácticas y patrones UnitTesting](https://www.amazon.com/gp/product/1617296279/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617296279&linkId=74c75cfae3a5aaccae3a5a) +* [Desarrollo basado en pruebas: Ejemplo](https://www.amazon.com/gp/product/0321146530/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321146530&linkId=5c63a93d8c1175b47caef50875) diff --git a/localization/ar/async-method-invocation/README.md b/localization/ar/async-method-invocation/README.md new file mode 100644 index 000000000000..05173d7d6104 --- /dev/null +++ b/localization/ar/async-method-invocation/README.md @@ -0,0 +1,178 @@ +--- +title: Async Method Invocation +shortTitle: Async Method Invocation +category: Concurrency +language: ar +tag: + - Reactive +--- + +## الغرض + +الاستدعاء غير المتزامن للطرق (invocación de método asincrónico) هو نمط حيث لا يتم حظر الخيط أو العملية التي تستدعي الطريقة أثناء انتظار النتائج. يوفر النمط معالجة متوازية للمهام المستقلة المتعددة ويسترجع النتائج عبر +التعريفات الراجعة (callbacks) أو بالانتظار حتى ينتهي الإجراء. + +## الشرح + +مثال يومي + +> إطلاق الصواريخ الفضائية هو عمل مثير. يعطي قائد المهمة أمر الإطلاق و +> بعد فترة غير محددة من الوقت، يتم إطلاق الصاروخ بنجاح أو يفشل بشكل كارثي. + +بعبارة أخرى + +> يستدعي الاستدعاء غير المتزامن للطرق الإجراء ويعود فورًا قبل أن تنتهي المهمة +> يتم إرجاع نتائج الإجراء لاحقًا إلى الاستدعاء (callback). + +حسب ويكيبيديا + +> في البرمجة متعددة العمليات، يعتبر استدعاء الطريقة غير المتزامن (AMI)، المعروف أيضًا بـ +> الاستدعاءات غير المتزامنة أو النمط غير المتزامن هو نمط تصميم حيث لا يتم حظر مكان الاستدعاء +> أثناء انتظار انتهاء الكود المستدعى. بدلاً من ذلك، يتم إخطار خيط الاستدعاء عندما تصل الاستجابة. الاستطلاع للحصول على إجابة هو خيار غير مرغوب فيه. + +**مثال برمجي** + +في هذا المثال، نحن نطلق صواريخ فضائية وننشر مركبات قمرية. + +تُظهر التطبيق ما يفعله نمط الاستدعاء غير المتزامن للطريقة. الأجزاء الرئيسية للنمط هي +`AsyncResult` الذي يعد حاوية وسيطة لقيمة تم تقييمها بشكل غير متزامن، +`AsyncCallback` الذي يمكن توفيره ليتم تنفيذه عند اكتمال المهمة و `AsyncExecutor` الذي +يدير تنفيذ المهام غير المتزامنة. + + +```java +public interface AsyncResult { + boolean isCompleted(); + T getValue() throws ExecutionException; + void await() throws InterruptedException; +} +``` + +```java +public interface AsyncCallback { + void onComplete(T value, Optional ex); +} +``` + +```java +public interface AsyncExecutor { + AsyncResult startProcess(Callable task); + AsyncResult startProcess(Callable task, AsyncCallback callback); + T endProcess(AsyncResult asyncResult) throws ExecutionException, InterruptedException; +} +``` + +`ThreadAsyncExecutor` هو تنفيذ لـ `AsyncExecutor`. يتم تسليط الضوء على بعض من أجزائه الرئيسية أدناه. + + +```java +public class ThreadAsyncExecutor implements AsyncExecutor { + + @Override + public AsyncResult startProcess(Callable task) { + return startProcess(task, null); + } + + @Override + public AsyncResult startProcess(Callable task, AsyncCallback callback) { + var result = new CompletableResult<>(callback); + new Thread( + () -> { + try { + result.setValue(task.call()); + } catch (Exception ex) { + result.setException(ex); + } + }, + "executor-" + idx.incrementAndGet()) + .start(); + return result; + } + + @Override + public T endProcess(AsyncResult asyncResult) + throws ExecutionException, InterruptedException { + if (!asyncResult.isCompleted()) { + asyncResult.await(); + } + return asyncResult.getValue(); + } +} +``` + +الآن كل شيء جاهز لإطلاق بعض الصواريخ لرؤية كيف يعمل كل شيء. + + +```java +public static void main(String[] args) throws Exception { + // الآن كل شيء جاهز لإطلاق بعض الصواريخ لرؤية كيف يعمل كل شيء. + + var executor = new ThreadAsyncExecutor(); + + // يبدأ بعض المهام غير المتزامنة بأوقات معالجة مختلفة، اثنان من الأخيرين مع محركات استرجاع (callback handlers) + + final var asyncResult1 = executor.startProcess(lazyval(10, 500)); + final var asyncResult2 = executor.startProcess(lazyval("test", 300)); + final var asyncResult3 = executor.startProcess(lazyval(50L, 700)); + final var asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Desplegando el rover lunar")); + final var asyncResult5 = + executor.startProcess(lazyval("devolución de llamada callback", 600), callback("Desplegando el rover lunar")); + + // يحاكي المعالجة في الخيط أو العملية الحالية بينما يتم تنفيذ المهام غير المتزامنة في خيوط أو عملياتها الخاصة + + Subproceso.dormir(350); // هيه، نحن نعمل بجد هنا + + log("قائد المهمة يشرب القهوة +"); + + // ينتظر حتى اكتمال المهام + + final var result1 = executor.endProcess(asyncResult1); + final var result2 = executor.endProcess(asyncResult2); + final var result3 = executor.endProcess(asyncResult3); + asyncResult4.await(); + asyncResult5.await(); + +// يسجل نتائج المهام، يتم تسجيل الاسترجاعات فور اكتمالها +log("الصاروخ الفضائي <" + resultado1 + "> أكمل إطلاقه"); +log("الصاروخ الفضائي <" + resultado2 + "> أكمل إطلاقه"); +log("الصاروخ الفضائي <" + result3 + "> أكمل إطلاقه"); + +} +``` + +Here is the output from the program console. + +```java +21:47:08.227 [executor-2] INFO com.iluwatar.async.method.invocation.App - الصاروخ الفضائي تم إطلاقه بنجاح +21:47:08.269 [main] INFO com.iluwatar.async.method.invocation.App - قائد المهمة يشرب القهوة +21:47:08.318 [executor-4] INFO com.iluwatar.async.method.invocation.App - الصاروخ الفضائي <20> تم إطلاقه بنجاح +21:47:08.335 [executor-4] INFO com.iluwatar.async.method.invocation.App - نشر الروفر القمري <20> +21:47:08.414 [executor-1] INFO com.iluwatar.async.method.invocation.App - الصاروخ الفضائي <10> تم إطلاقه بنجاح +21:47:08.519 [executor-5] INFO com.iluwatar.async.method.invocation.App - الصاروخ الفضائي تم إطلاقه بنجاح +21:47:08.519 [executor-5] INFO com.iluwatar.async.method.invocation.App - تنفيذ المركبة القمرية +21:47:08.616 [executor-3] INFO com.iluwatar.async.method.invocation.App - الصاروخ الفضائي <50> تم إطلاقه بنجاح +21:47:08.617 [main] INFO com.iluwatar.async.method.invocation.App - إطلاق الصاروخ الفضائي <10> تم +21:47:08.617 [main] INFO com.iluwatar.async.method.invocation.App - إطلاق الصاروخ الفضائي تم +21:47:08.618 [main] INFO com.iluwatar.async.method.invocation.App - إطلاق الصاروخ الفضائي <50> تم + +``` + +# مخطط الفئة + +![texto alternativo](./etc/async-method-invocation.png "Invocación de método asíncrono") + +## القابلية للتطبيق + +استخدم نمط استدعاء الطريقة غير المتزامنة عندما + +* يكون لديك مهام مستقلة متعددة يمكن تنفيذها بشكل متوازٍ +* تحتاج إلى تحسين أداء مجموعة من المهام المتسلسلة +* لديك قدرة معالجة محدودة أو مهام تنفيذ طويلة الأمد ولا ينبغي أن تنتظر الدعوة حتى تصبح المهام جاهزة + +## أمثلة يومية + +* [FutureTask](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html) +* [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) +* [ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) +* [Patrón asíncrono basado en tareas](https://msdn.microsoft.com/en-us/library/hh873175.aspx) diff --git a/localization/ar/async-method-invocation/etc/async-method-invocation.png b/localization/ar/async-method-invocation/etc/async-method-invocation.png new file mode 100644 index 000000000000..764895d7a217 Binary files /dev/null and b/localization/ar/async-method-invocation/etc/async-method-invocation.png differ diff --git a/localization/ar/balking/README.md b/localization/ar/balking/README.md new file mode 100644 index 000000000000..c43480d580bd --- /dev/null +++ b/localization/ar/balking/README.md @@ -0,0 +1,135 @@ +--- +title: Balking +shortTitle: Balking +category: Concurrency +language: ar +tag: + - Decoupling +--- + +## الغرض + +يتم استخدام نمط _Balking_ لمنع كائن من تنفيذ كود معين إذا كان في حالة غير مكتملة أو غير مناسبة. + +## الشرح + +مثال من الحياة الواقعية + +> في غسالة الملابس هناك زر بدء لتشغيل غسل الملابس. عندما تكون الغسالة غير نشطة، يعمل الزر كما هو متوقع، ولكن إذا كانت الغسالة تغسل بالفعل، فإن الزر لا يفعل شيئًا. + +بمعنى آخر + +> باستخدام نمط _Balking_، يتم تنفيذ كود معين فقط إذا كان الكائن في حالة معينة. + +تقول ويكيبيديا + +> نمط _Balking_ هو نمط تصميم برمجي ينفذ إجراء على كائن فقط عندما يكون الكائن في حالة معينة. على سبيل المثال، إذا كان الكائن يقرأ ملفات ZIP واستدعى أسلوب _get_ على الكائن عندما لا يكون الملف ZIP مفتوحًا، فإن الكائن "يرفض" (_balk_) الطلب. + +**مثال برمجي** + +في هذا المثال من التنفيذ، `WashingMachine` هو كائن له حالتان يمكن أن يكونا: _ENABLED_ و _WASHING_ (مفعل و يغسل على التوالي). إذا كانت الغسالة في حالة _ENABLED_، فإن الحالة تتغير إلى _WASHING_ باستخدام طريقة آمنة ضد الخيوط (thread-safe). من ناحية أخرى، إذا كانت الغسالة بالفعل تغسل وأي خيط آخر ينفذ `wash()`، فلن يتم تغيير الحالة وتنتهي تنفيذ الطريقة دون القيام بأي شيء. + +إليك الأجزاء ذات الصلة من فئة `WashingMachine`. + + +```java +@Slf4j +public class WashingMachine { + + private final DelayProvider delayProvider; + private WashingMachineState washingMachineState; + + public WashingMachine(DelayProvider delayProvider) { + this.delayProvider = delayProvider; + this.washingMachineState = WashingMachineState.ENABLED; + } + + public WashingMachineState getWashingMachineState() { + return washingMachineState; + } + + public void wash() { + synchronized (this) { + var machineState = getWashingMachineState(); + LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState); + if (this.washingMachineState == WashingMachineState.WASHING) { + LOGGER.error("Cannot wash if the machine has been already washing!"); + return; + } + this.washingMachineState = WashingMachineState.WASHING; + } + LOGGER.info("{}: Doing the washing", Thread.currentThread().getName()); + this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing); + } + + public synchronized void endOfWashing() { + washingMachineState = WashingMachineState.ENABLED; + LOGGER.info("{}: Washing completed.", Thread.currentThread().getId()); + } +} +``` + +هنا الواجهة البسيطة `DelayProvider` المستخدمة من قبل `WashingMachine`. + + +```java +public interface DelayProvider { + void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task); +} +``` + +الآن نقدم التطبيق باستخدام `WashingMachine`. + + +```java +public static void main(String... args) { + final var washingMachine = new WashingMachine(); + var executorService = Executors.newFixedThreadPool(3); + for (int i = 0; i < 3; i++) { + executorService.execute(washingMachine::wash); + } + executorService.shutdown(); + try { + executorService.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException ie) { + LOGGER.error("ERROR: Waiting on executor service shutdown!"); + Thread.currentThread().interrupt(); + } +} +``` + +إليك مخرجات التطبيق في وحدة التحكم. + + +``` +14:02:52.268 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Actual machine state: ENABLED +14:02:52.272 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Doing the washing +14:02:52.272 [pool-1-thread-3] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-3: Actual machine state: WASHING +14:02:52.273 [pool-1-thread-3] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing! +14:02:52.273 [pool-1-thread-1] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-1: Actual machine state: WASHING +14:02:52.273 [pool-1-thread-1] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing! +14:02:52.324 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - 14: Washing completed. +``` + +## مخطط الفئات + + +![alt text](./etc/balking.png "Balking") + +## القابلية للتطبيق + +استخدم نمط _Balking_ عندما + +* يجب على كائن تنفيذ كود معين فقط عندما يكون في حالة معينة. +* الكائنات في حالة معرضة للتوقف مؤقتًا، ولكن لفترة زمنية غير محددة. + +## الأنماط ذات الصلة + + +* [Guarded Suspension Pattern](https://java-design-patterns.com/patterns/guarded-suspension/) +* [Double Checked Locking Pattern](https://java-design-patterns.com/patterns/double-checked-locking/) + +## المراجع + + +* [Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML, 2nd Edition, Volume 1](https://www.amazon.com/gp/product/0471227293/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0471227293&linkId=0e39a59ffaab93fb476036fecb637b99) diff --git a/localization/ar/balking/etc/balking.png b/localization/ar/balking/etc/balking.png new file mode 100644 index 000000000000..f409eaacbb95 Binary files /dev/null and b/localization/ar/balking/etc/balking.png differ diff --git a/localization/ar/bridge/README.md b/localization/ar/bridge/README.md new file mode 100644 index 000000000000..2c47f65ea747 --- /dev/null +++ b/localization/ar/bridge/README.md @@ -0,0 +1,216 @@ +--- +title: Bridge +shortTitle: Bridge +category: Structural +language: ar +tag: + - Gang of Four +--- + +## أيضًا معروف باسم + +Handle/Body + +## الهدف + +فصل التجريد عن تنفيذه بحيث يمكن لكل منهما التغيير بشكل مستقل. + +## الشرح + +مثال من الحياة الواقعية + +> تخيل أن لديك سلاحًا مع تعاويذ مختلفة، ومن المفترض أن تسمح بخلط أسلحة مختلفة مع تعاويذ مختلفة. ماذا ستفعل؟ هل ستقوم بإنشاء نسخ متعددة من كل سلاح لكل تعويذة من التعاويذ أو ببساطة تقوم بإنشاء تعويذة منفصلة وتحددها للسلاح حسب الحاجة؟ نمط Bridge يتيح لك القيام بالأمر الثاني. + +ببساطة + +> يتعلق نمط Bridge بتفضيل التركيب على الوراثة. يتم دفع تفاصيل التنفيذ من هرم إلى كائن آخر مع هرم منفصل. + +تقول ويكيبيديا + +> نمط Bridge هو نمط تصميم يستخدم في هندسة البرمجيات يهدف إلى "فصل التجريد عن تنفيذه بحيث يمكن لكل منهما التغيير بشكل مستقل." + +**مثال برمجي** + +نقلًا لمثال السلاح المذكور أعلاه. هنا لدينا واجهة السلاح `Weapon`: + + +```java +public interface Weapon { + void wield(); + void swing(); + void unwield(); + Enchantment getEnchantment(); +} + +public class Sword implements Weapon { + + private final Enchantment enchantment; + + public Sword(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The sword is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The sword is swinged."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The sword is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} + +public class Hammer implements Weapon { + + private final Enchantment enchantment; + + public Hammer(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The hammer is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The hammer is swinged."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The hammer is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} +``` + +إليك واجهة التعاويذ `Enchantment` المنفصلة: + + +```java +public interface Enchantment { + void onActivate(); + void apply(); + void onDeactivate(); +} + +public class FlyingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item begins to glow faintly."); + } + + @Override + public void apply() { + LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand."); + } + + @Override + public void onDeactivate() { + LOGGER.info("The item's glow fades."); + } +} + +public class SoulEatingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item spreads bloodlust."); + } + + @Override + public void apply() { + LOGGER.info("The item eats the soul of enemies."); + } + + @Override + public void onDeactivate() { + LOGGER.info("Bloodlust slowly disappears."); + } +} +``` + +إليك كلا الواجهتين في العمل: + + +```java +LOGGER.info("The knight receives an enchanted sword."); +var enchantedSword = new Sword(new SoulEatingEnchantment()); +enchantedSword.wield(); +enchantedSword.swing(); +enchantedSword.unwield(); + +LOGGER.info("The valkyrie receives an enchanted hammer."); +var hammer = new Hammer(new FlyingEnchantment()); +hammer.wield(); +hammer.swing(); +hammer.unwield(); +``` + +إليك مخرجات التطبيق في وحدة التحكم. + + +``` +The knight receives an enchanted sword. +The sword is wielded. +The item spreads bloodlust. +The sword is swung. +The item eats the soul of enemies. +The sword is unwielded. +Bloodlust slowly disappears. +The valkyrie receives an enchanted hammer. +The hammer is wielded. +The item begins to glow faintly. +The hammer is swung. +The item flies and strikes the enemies finally returning to owner's hand. +The hammer is unwielded. +The item's glow fades. +``` + +## مخطط الفئات + + +![alt text](./etc/bridge.urm.png "Bridge diagrama de clases") + +## القابلية للتطبيق + +استخدم نمط Bridge عندما + +* ترغب في تجنب الربط الدائم بين التجريد وتنفيذه. قد يكون هذا هو الحال، على سبيل المثال، عندما يجب اختيار أو تغيير التنفيذ في وقت التشغيل. +* يجب أن تكون كل من التجريدات وتنفيذاتها قابلة للتوسيع عبر الوراثة. في هذه الحالة، يتيح لك نمط Bridge دمج التجريدات والتنفيذات المختلفة وتوسيعها بشكل مستقل. +* يجب ألا تؤثر التغييرات في تنفيذ التجريد على العملاء؛ أي أنه لا يجب أن يحتاج الكود الخاص بهم إلى إعادة تجميع. +* لديك تكاثر في الفئات. تشير مثل هذه الهرميات إلى الحاجة إلى تقسيم كائن إلى جزئين. يستخدم Rumbaugh مصطلح "التعميمات المتداخلة" للإشارة إلى مثل هذه الهرميات من الفئات. +* ترغب في مشاركة تنفيذ بين عدة كائنات (ربما باستخدام عد مرجعي)، ويجب إخفاء هذه الحقيقة عن العميل. مثال بسيط هو فئة String لـ Coplien، حيث يمكن لعدة كائنات مشاركة نفس تمثيل السلسلة. + +## الدروس التعليمية + +* [Bridge Pattern Tutorial](https://www.journaldev.com/1491/bridge-design-pattern-java) + +## الاعتمادات + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) diff --git a/localization/ar/bridge/etc/bridge.urm.png b/localization/ar/bridge/etc/bridge.urm.png new file mode 100644 index 000000000000..785585bf8163 Binary files /dev/null and b/localization/ar/bridge/etc/bridge.urm.png differ diff --git a/localization/ar/builder/README.md b/localization/ar/builder/README.md new file mode 100644 index 000000000000..1edfb4b826db --- /dev/null +++ b/localization/ar/builder/README.md @@ -0,0 +1,147 @@ +--- +title: Builder +shortTitle: Builder +category: Creational +language: ar +tag: + - Gang of Four +--- + +## الهدف + +فصل بناء كائن معقد عن تمثيله بحيث يمكن لنفس عملية البناء إنشاء تمثيلات مختلفة. + +## الشرح + +مثال من الحياة الواقعية + +> تخيل مولد شخصيات للعبة تقمص أدوار. الخيار الأسهل هو السماح للكمبيوتر بإنشاء الشخصية نيابة عنك. إذا أردت تحديد تفاصيل الشخصية يدويًا مثل المهنة، الجنس، لون الشعر، إلخ، فإن إنشاء الشخصية يصبح عملية خطوة بخطوة تكتمل عندما تكون جميع الاختيارات جاهزة. + +ببساطة + +> يسمح بإنشاء نكهات مختلفة من كائن دون تلويث الباني. مفيد عندما يمكن أن يكون هناك عدة نكهات لكائن ما، أو عندما تكون هناك العديد من الخطوات المعنية في إنشاء الكائن. + +تقول ويكيبيديا + +> نمط البناء هو نمط تصميم برمجي لإنشاء الكائنات بهدف إيجاد حل لمضاد النمط الخاص بالباني المنطقي. + +مع ذلك، دعني أضيف بعض المعلومات حول ما هو مضاد النمط للباني المنطقي. في وقت ما أو آخر، رأينا جميعًا بانيًا مثل التالي: + + +```java +public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) { +} +``` + +كما ترى، قد يخرج عدد معلمات الباني عن السيطرة بسرعة، وقد يصبح من الصعب فهم ترتيب المعلمات. بالإضافة إلى ذلك، قد تستمر هذه القائمة في النمو إذا أردت إضافة المزيد من الخيارات في المستقبل. يسمى هذا مضاد النمط للباني المنطقي. + +**مثال برمجي** + +البديل الحكيم هو استخدام نمط Builder. أولاً، لدينا بطلنا `Hero` الذي نريد إنشائه: + + +```java +public final class Hero { + private final Profession profession; + private final String name; + private final HairType hairType; + private final HairColor hairColor; + private final Armor armor; + private final Weapon weapon; + + private Hero(Builder builder) { + this.profession = builder.profession; + this.name = builder.name; + this.hairColor = builder.hairColor; + this.hairType = builder.hairType; + this.weapon = builder.weapon; + this.armor = builder.armor; + } +} +``` + +ثم لدينا الباني: + + +```java + public static class Builder { + private final Profession profession; + private final String name; + private HairType hairType; + private HairColor hairColor; + private Armor armor; + private Weapon weapon; + + public Builder(Profession profession, String name) { + if (profession == null || name == null) { + throw new IllegalArgumentException("profession and name can not be null"); + } + this.profession = profession; + this.name = name; + } + + public Builder withHairType(HairType hairType) { + this.hairType = hairType; + return this; + } + + public Builder withHairColor(HairColor hairColor) { + this.hairColor = hairColor; + return this; + } + + public Builder withArmor(Armor armor) { + this.armor = armor; + return this; + } + + public Builder withWeapon(Weapon weapon) { + this.weapon = weapon; + return this; + } + + public Hero build() { + return new Hero(this); + } + } +``` + +إذن يمكن استخدامه كما يلي: + + +```java +var mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build(); +``` + +## مخطط الفئات + +![alt text](./etc/builder.urm.png "مخطط فئات Builder") + +## القابلية للتطبيق + +استخدم نمط Builder عندما + +* يجب أن يكون الخوارزمية لإنشاء كائن معقدة مستقلة عن الأجزاء التي تتكون منها الكائن وكيفية تجميعها. +* يجب أن تسمح عملية البناء بتمثيلات مختلفة للكائن الذي يتم بناؤه. + +## الدروس التعليمية + +* [Refactoring Guru](https://refactoring.guru/design-patterns/builder) +* [مدونة Oracle](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) +* [Journal Dev](https://www.journaldev.com/1425/builder-design-pattern-in-java) + +## الاستخدامات في العالم الواقعي + +* [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html) +* [java.nio.ByteBuffer](http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte-) بالإضافة إلى غيرها من المخازن المؤقتة مثل FloatBuffer و IntBuffer، إلخ. +* [java.lang.StringBuffer](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html#append-boolean-) +* جميع التطبيقات من [java.lang.Appendable](http://docs.oracle.com/javase/8/docs/api/java/lang/Appendable.html) +* [بناة Apache Camel](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder) +* [Apache Commons Option.Builder](https://commons.apache.org/proper/commons-cli/apidocs/org/apache/commons/cli/Option.Builder.html) + +## الاعتمادات + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) diff --git a/localization/ar/builder/etc/builder.urm.png b/localization/ar/builder/etc/builder.urm.png new file mode 100644 index 000000000000..d77808d36097 Binary files /dev/null and b/localization/ar/builder/etc/builder.urm.png differ diff --git a/localization/ar/business-delegate/README.md b/localization/ar/business-delegate/README.md new file mode 100644 index 000000000000..13fe05b32db3 --- /dev/null +++ b/localization/ar/business-delegate/README.md @@ -0,0 +1,194 @@ +--- +title: Business Delegate +shortTitle: Business Delegate +category: Structural +language: ar +tag: + - Decoupling +--- + +## الغرض + +نمط **Business Delegate** يضيف طبقة من التجريد بين مستويات العرض والأعمال. باستخدام هذا النمط، نحقق ارتباطًا مرنًا بين المستويات ونعزل المعرفة حول كيفية تحديد المواقع والاتصال والتفاعل مع الكائنات التجارية التي تشكل التطبيق. + +## أيضًا معروف باسم + +مُمثل الخدمة + +## الشرح + +مثال من العالم الحقيقي + +> تطبيق للهواتف المحمولة يعد ببث أي فيلم موجود إلى جهازك. يقوم التطبيق بالتقاط سلسلة البحث من المستخدم ويمررها إلى **Business Delegate**. يقوم **Business Delegate** باختيار خدمة البث الأكثر ملاءمة ويبدأ في تشغيل الفيديو. + +بكلمات أبسط + +> يضيف **Business Delegate** طبقة من التجريد بين مستويات العرض والأعمال. + +تقول ويكيبيديا + +> **Business Delegate** هو نمط تصميم في Java EE. هذا النمط يهدف إلى تقليل الترابط بين خدمات الأعمال ومستوى العرض المتصل، وإخفاء تفاصيل التنفيذ الخاصة بالخدمات (بما في ذلك البحث والوصول إلى بنية EJB). يعمل **Business Delegate** كـ **مهايئ** لاستدعاء كائنات الأعمال من طبقة العرض. + +**مثال برمجي** + +أولاً، لدينا تجريد لخدمات البث عبر الفيديو `VideoStreamingService` مع زوج من التطبيقات `NetflixService` و `YouTubeService`. + + +```java +public interface VideoStreamingService { + void doProcessing(); +} + +@Slf4j +public class NetflixService implements VideoStreamingService { + @Override + public void doProcessing() { + LOGGER.info("NetflixService is now processing"); + } +} + +@Slf4j +public class YouTubeService implements VideoStreamingService { + @Override + public void doProcessing() { + LOGGER.info("YouTubeService is now processing"); + } +} +``` + +التالي، لدينا خدمة البحث `BusinessLookup` التي تقرر أي خدمة بث الفيديو يجب استخدامها. + + +```java + +@Setter +public class BusinessLookup { + + private NetflixService netflixService; + private YouTubeService youTubeService; + + public VideoStreamingService getBusinessService(String movie) { + if (movie.toLowerCase(Locale.ROOT).contains("die hard")) { + return netflixService; + } else { + return youTubeService; + } + } +} +``` + +يستخدم **Delegado de Negocio** `BusinessDelegate` بحث الأعمال لتوجيه طلبات تشغيل الأفلام إلى خدمة بث الفيديو المناسبة. + + +```java + +@Setter +public class BusinessDelegate { + + private BusinessLookup lookupService; + + public void playbackMovie(String movie) { + VideoStreamingService videoStreamingService = lookupService.getBusinessService(movie); + videoStreamingService.doProcessing(); + } +} +``` + +العميل المحمول `MobileClient` يستخدم **Business Delegate** لاستدعاء مستوى الأعمال. + + +```java +public class MobileClient { + + private final BusinessDelegate businessDelegate; + + public MobileClient(BusinessDelegate businessDelegate) { + this.businessDelegate = businessDelegate; + } + + public void playbackMovie(String movie) { + businessDelegate.playbackMovie(movie); + } +} +``` + +أخيرًا، يمكننا عرض المثال الكامل أثناء التنفيذ. + + +```java + public static void main(String[]args){ + + // preparar los objetos + var businessDelegate=new BusinessDelegate(); + var businessLookup=new BusinessLookup(); + businessLookup.setNetflixService(new NetflixService()); + businessLookup.setYouTubeService(new YouTubeService()); + businessDelegate.setLookupService(businessLookup); + + // crear el cliente y utilizar el Business Delegate + var client=new MobileClient(businessDelegate); + client.playbackMovie("Die Hard 2"); + client.playbackMovie("Maradona: The Greatest Ever"); + } +``` + +إليك مخرجات وحدة التحكم. + + +``` +21:15:33.790 [main] INFO com.iluwatar.business.delegate.NetflixService - NetflixService is now processing +21:15:33.794 [main] INFO com.iluwatar.business.delegate.YouTubeService - YouTubeService is now processing +``` + +## مخطط الفئات + +![مخطط الفئات](./etc/business-delegate.urm.png "Business Delegate") + +## الأنماط ذات الصلة + +* [نمط تحديد الموقع للخدمات](https://java-design-patterns.com/patterns/service-locator/) + +## القابلية للتطبيق + +استخدم نمط Business Delegate عندما + +* ترغب في تقليل الترابط بين مستويات العرض والأعمال. +* ترغب في تنسيق المكالمات إلى خدمات أعمال متعددة. +* ترغب في تجميع عمليات البحث والمكالمات إلى الخدمات. +* من الضروري تجريد وتغليف الاتصال بين طبقة العميل وخدمات الأعمال. + +## دروس + +* [نمط Business Delegate في TutorialsPoint](https://www.tutorialspoint.com/design_pattern/business_delegate_pattern.htm) + +## الاستخدامات المعروفة + +* التطبيقات المؤسسية التي تستخدم Java EE (Java Platform, Enterprise Edition) +* التطبيقات التي تتطلب الوصول عن بُعد إلى خدمات الأعمال + +## العواقب + +الفوائد: + +* فك الترابط بين مستويات العرض والأعمال: يسمح بمواصلة تطور مستوى العميل والخدمات المؤسسية بشكل مستقل. +* شفافية الموقع: لا يتأثر العملاء بتغييرات الموقع أو التهيئة لخدمات الأعمال. +* إعادة الاستخدام وقابلية التوسع: يمكن إعادة استخدام كائنات Business Delegate بواسطة عملاء متعددين، ويدعم النمط التوازن في الحمل وقابلية التوسع. + +العيوب: + +* التعقيد: يضيف طبقات وتجريدات إضافية قد تزيد من التعقيد. +* تحميل الأداء: قد يؤدي الإشارة الإضافية إلى خفض طفيف في الأداء. + +## الأنماط ذات الصلة + +* [محدد خدمات](https://java-design-patterns.com/patterns/service-locator/): يستخدم Delegado de Negocio ( + Business Delegate) محدد خدمات (Service Locator) للعثور على خدمات الأعمال. +* [واجهة الجلسة](https://java-design-patterns.com/patterns/session-facade/): يمكن لـ Delegado de Negocio (Business + Delegate) استخدام واجهة الجلسة (Session Facade) لتوفير واجهة موحدة لمجموعة من خدمات الأعمال. +* [كائن مركب](https://java-design-patterns.com/patterns/composite-entity/): يمكن لـ Delegado de Negocio (Business Delegate) + استخدام الكائن المركب (Composite Entity) لإدارة حالة خدمات الأعمال. + +## الشكر + +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Core J2EE Patterns: Best Practices and Design Strategies](https://www.amazon.com/gp/product/0130648841/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0130648841&linkId=a0100de2b28c71ede8db1757fb2b5947) diff --git a/localization/ar/business-delegate/etc/business-delegate.urm.png b/localization/ar/business-delegate/etc/business-delegate.urm.png new file mode 100644 index 000000000000..4dca6c263b99 Binary files /dev/null and b/localization/ar/business-delegate/etc/business-delegate.urm.png differ diff --git a/localization/ar/bytecode/README.md b/localization/ar/bytecode/README.md new file mode 100644 index 000000000000..d5c046b4fccf --- /dev/null +++ b/localization/ar/bytecode/README.md @@ -0,0 +1,264 @@ +--- +title: Bytecode +shortTitle: Bytecode +category: Behavioral +language: ar +tag: + - Game programming +--- + +## الغرض + +يسمح بترميز السلوك كتعليمات لجهاز افتراضي. + +## الشرح + +مثال من العالم الواقعي + +> فريق يعمل على لعبة جديدة حيث يتقاتل السحرة مع بعضهم البعض. يحتاج سلوك السحرة إلى تعديل دقيق وتجربة مئات المرات من خلال اختبارات اللعبة. ليس من المثالي أن يطلب من المبرمج إجراء تغييرات في كل مرة يريد فيها مصمم اللعبة تعديل السلوك، لذلك يتم تنفيذ سلوك الساحر كجهاز افتراضي يعتمد على البيانات. + +بكلمات بسيطة + +> نمط Bytecode يسمح بسلوك موجه بالبيانات بدلاً من الكود. + +[Gameprogrammingpatterns.com](https://gameprogrammingpatterns.com/bytecode.html) يوضح الوثائق: + +> مجموعة من التعليمات تحدد العمليات منخفضة المستوى التي يمكن تنفيذها. يتم ترميز سلسلة من التعليمات كدورة من البايتات. يقوم الجهاز الافتراضي بتنفيذ هذه التعليمات واحدة تلو الأخرى، باستخدام مكدس للقيم الوسيطة. يسمح الجمع بين التعليمات بتعريف سلوكيات معقدة وعالية المستوى. + +**مثال برمجي** + +أحد الكائنات الأكثر أهمية في اللعبة هو فئة ماغو `Wizard`. + + +```java + +@AllArgsConstructor +@Setter +@Getter +@Slf4j +public class Wizard { + + private int health; + private int agility; + private int wisdom; + private int numberOfPlayedSounds; + private int numberOfSpawnedParticles; + + public void playSound() { + LOGGER.info("Playing sound"); + numberOfPlayedSounds++; + } + + public void spawnParticles() { + LOGGER.info("Spawning particles"); + numberOfSpawnedParticles++; + } +} +``` + +بعد ذلك، نعرض التعليمات المتاحة لجهازنا الافتراضي. لكل تعليمات دلالتها الخاصة حول كيفية التعامل مع بيانات المكدس. على سبيل المثال، تقوم التعليمة ADD بأخذ العنصرين العلويين من المكدس، وتجمعهما، ثم تضع النتيجة في المكدس. + + +```java + +@AllArgsConstructor +@Getter +public enum Instruction { + + LITERAL(1), // e.g. "LITERAL 0", push 0 to stack + SET_HEALTH(2), // e.g. "SET_HEALTH", pop health and wizard number, call set health + SET_WISDOM(3), // e.g. "SET_WISDOM", pop wisdom and wizard number, call set wisdom + SET_AGILITY(4), // e.g. "SET_AGILITY", pop agility and wizard number, call set agility + PLAY_SOUND(5), // e.g. "PLAY_SOUND", pop value as wizard number, call play sound + SPAWN_PARTICLES(6), // e.g. "SPAWN_PARTICLES", pop value as wizard number, call spawn particles + GET_HEALTH(7), // e.g. "GET_HEALTH", pop value as wizard number, push wizard's health + GET_AGILITY(8), // e.g. "GET_AGILITY", pop value as wizard number, push wizard's agility + GET_WISDOM(9), // e.g. "GET_WISDOM", pop value as wizard number, push wizard's wisdom + ADD(10), // e.g. "ADD", pop 2 values, push their sum + DIVIDE(11); // e.g. "DIVIDE", pop 2 values, push their division + // ... +} +``` + +في قلب مثالنا توجد فئة `VirtualMachine`. تأخذ التعليمات كمدخلات وتنفذها لتوفير سلوك كائن اللعبة. + + +```java + +@Getter +@Slf4j +public class VirtualMachine { + + private final Stack stack = new Stack<>(); + + private final Wizard[] wizards = new Wizard[2]; + + public VirtualMachine() { + wizards[0] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32), + 0, 0); + wizards[1] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32), + 0, 0); + } + + public VirtualMachine(Wizard wizard1, Wizard wizard2) { + wizards[0] = wizard1; + wizards[1] = wizard2; + } + + public void execute(int[] bytecode) { + for (var i = 0; i < bytecode.length; i++) { + Instruction instruction = Instruction.getInstruction(bytecode[i]); + switch (instruction) { + case LITERAL: + // Read the next byte from the bytecode. + int value = bytecode[++i]; + // Push the next value to stack + stack.push(value); + break; + case SET_AGILITY: + var amount = stack.pop(); + var wizard = stack.pop(); + setAgility(wizard, amount); + break; + case SET_WISDOM: + amount = stack.pop(); + wizard = stack.pop(); + setWisdom(wizard, amount); + break; + case SET_HEALTH: + amount = stack.pop(); + wizard = stack.pop(); + setHealth(wizard, amount); + break; + case GET_HEALTH: + wizard = stack.pop(); + stack.push(getHealth(wizard)); + break; + case GET_AGILITY: + wizard = stack.pop(); + stack.push(getAgility(wizard)); + break; + case GET_WISDOM: + wizard = stack.pop(); + stack.push(getWisdom(wizard)); + break; + case ADD: + var a = stack.pop(); + var b = stack.pop(); + stack.push(a + b); + break; + case DIVIDE: + a = stack.pop(); + b = stack.pop(); + stack.push(b / a); + break; + case PLAY_SOUND: + wizard = stack.pop(); + getWizards()[wizard].playSound(); + break; + case SPAWN_PARTICLES: + wizard = stack.pop(); + getWizards()[wizard].spawnParticles(); + break; + default: + throw new IllegalArgumentException("Invalid instruction value"); + } + LOGGER.info("Executed " + instruction.name() + ", Stack contains " + getStack()); + } + } + + public void setHealth(int wizard, int amount) { + wizards[wizard].setHealth(amount); + } + // other setters -> + // ... +} +``` + +الآن يمكننا عرض المثال الكامل باستخدام الآلة الافتراضية. + +```java + public static void main(String[]args){ + + var vm=new VirtualMachine( + new Wizard(45,7,11,0,0), + new Wizard(36,18,8,0,0)); + + vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0")); + vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0")); + vm.execute(InstructionConverterUtil.convertToByteCode("GET_HEALTH")); + vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0")); + vm.execute(InstructionConverterUtil.convertToByteCode("GET_AGILITY")); + vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0")); + vm.execute(InstructionConverterUtil.convertToByteCode("GET_WISDOM")); + vm.execute(InstructionConverterUtil.convertToByteCode("ADD")); + vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 2")); + vm.execute(InstructionConverterUtil.convertToByteCode("DIVIDE")); + vm.execute(InstructionConverterUtil.convertToByteCode("ADD")); + vm.execute(InstructionConverterUtil.convertToByteCode("SET_HEALTH")); + } +``` + +إليك مخرجات وحدة التحكم. + + +``` +16:20:10.193 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0] +16:20:10.196 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 0] +16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_HEALTH, Stack contains [0, 45] +16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 0] +16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_AGILITY, Stack contains [0, 45, 7] +16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 7, 0] +16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_WISDOM, Stack contains [0, 45, 7, 11] +16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 45, 18] +16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 18, 2] +16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed DIVIDE, Stack contains [0, 45, 9] +16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 54] +16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed SET_HEALTH, Stack contains [] +``` + +## مخطط الفئات + + +![alt text](./etc/bytecode.urm.png "Bytecode class diagram") + +## القابلية للتطبيق + + +## القابلية للتطبيق + +استخدم نمط Bytecode عندما تحتاج إلى تعريف العديد من السلوكيات ولغة تنفيذ لعبتك ليست مناسبة لأن: + +* إنها منخفضة المستوى جدًا، مما يجعل البرمجة مملة أو عرضة للأخطاء. +* التكرار فيها يستغرق وقتًا طويلًا بسبب بطء وقت الترجمة أو مشاكل أخرى في الأدوات. +* إنها تحتوي على ثقة مفرطة. إذا كنت ترغب في التأكد من أن السلوك المحدد لا يمكن أن يتسبب في كسر اللعبة، يجب أن تفصله عن باقي قاعدة الكود. + +## الاستخدامات المعروفة + +* تستخدم Java Virtual Machine (JVM) bytecode لتمكين برامج Java من العمل على أي جهاز يحتوي على JVM. +* تقوم Python بترجمة سكربتاتها إلى bytecode، الذي يتم تفسيره بعد ذلك بواسطة آلة افتراضية Python. +* يستخدم .NET Framework نوعًا من bytecode يسمى Microsoft Intermediate Language (MSIL). + +## العواقب + +### المزايا: + +* القابلية للنقل: يمكن تنفيذ البرامج على أي منصة تحتوي على آلة افتراضية متوافقة. +* الأمان: يمكن للآلة الافتراضية تطبيق ضوابط أمان على كود البايت. +* الأداء: يمكن للمترجمات JIT تحسين كود البايت في وقت التشغيل، مما يحسن الأداء المحتمل مقارنة بالكود المفسر. + +### العيوب: + +* الحمل الزائد: تنفيذ bytecode يتضمن عادةً مزيدًا من الحمل الزائد مقارنةً بتنفيذ الكود الأصلي، مما قد يؤثر على الأداء. +* التعقيد: تنفيذ وصيانة آلة افتراضية يضيف تعقيدًا للنظام. + +## الأنماط المرتبطة + +* [مترجم](https://java-design-patterns.com/patterns/interpreter/) يستخدم غالبًا داخل تنفيذ آلات افتراضية لتفسير تعليمات bytecode. +* [أمر](https://java-design-patterns.com/patterns/command/): يمكن اعتبار تعليمات bytecode أوامر يتم تنفيذها بواسطة الآلة الافتراضية. +* [طريقة المصنع](https://java-design-patterns.com/patterns/factory-method/): قد تستخدم الآلات الافتراضية طرق المصنع لإنشاء العمليات أو التعليمات المحددة في bytecode. + +## الشكر + +* [أنماط برمجة الألعاب](http://gameprogrammingpatterns.com/bytecode.html) +* [برمجة لغات البرمجة](https://amzn.to/49Tusnn) diff --git a/localization/ar/bytecode/etc/bytecode.urm.png b/localization/ar/bytecode/etc/bytecode.urm.png new file mode 100644 index 000000000000..51335fa0a4b4 Binary files /dev/null and b/localization/ar/bytecode/etc/bytecode.urm.png differ diff --git a/localization/ar/chain-of-responsibility/README.md b/localization/ar/chain-of-responsibility/README.md new file mode 100644 index 000000000000..f3cc1a2f3b20 --- /dev/null +++ b/localization/ar/chain-of-responsibility/README.md @@ -0,0 +1,207 @@ +--- +title: Chain of responsibility +shortTitle: Chain of responsibility +category: Behavioral +language: ar +tag: + - Gang of Four + - Decoupling +--- + +## أيضًا معروف بـ + +* سلسلة الأوامر +* سلسلة الكائنات +* سلسلة المسؤولية + +## الغرض + +يمنع ربط مُرسل الطلب بمستقبله من خلال إعطاء أكثر من كائن الفرصة لإدارة الطلب. يربط الكائنات المستقبلية معًا ويمرر الطلب عبر السلسلة حتى يتمكن أحد الكائنات من معالجته. + +## الشرح + +مثال من الحياة الواقعية + +> الملك الأورك يعطي أوامر بصوت عالٍ لجيشه. أقرب شخص للرد هو القائد، ثم الضابط، ثم الجندي. القائد، الضابط، والجندي يشكلون سلسلة من المسؤولية. + +بكلمات بسيطة + +> يساعد في بناء سلسلة من الكائنات. يدخل الطلب من طرف ويتنقل عبر كائنات متعددة حتى يجد مديرًا مناسبًا. + +تقول ويكيبيديا + +> في التصميم الموجه للكائنات، نمط سلسلة المسؤولية هو نمط تصميم يتكون من مصدر لأوامر الكائنات وسلسلة من كائنات المعالجة. يحتوي كل كائن معالجة على منطق يحدد أنواع أوامر الكائنات التي يمكنه التعامل معها؛ يتم تمرير البقية إلى كائن المعالجة التالي في السلسلة. + +**مثال برمجي** + +ترجمة لمثالنا مع الأورك أعلاه. أولًا، لدينا الكلاس `Request`: + + +```java +import lombok.Getter; + +@Getter +public class Request { + + private final RequestType requestType; + private final String requestDescription; + private boolean handled; + + public Request(final RequestType requestType, final String requestDescription) { + this.requestType = Objects.requireNonNull(requestType); + this.requestDescription = Objects.requireNonNull(requestDescription); + } + + public void markHandled() { + this.handled = true; + } + + @Override + public String toString() { + return getRequestDescription(); + } +} + +public enum RequestType { + DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX +} +``` + +أدناه، نعرض تسلسل هرم مدير الطلبات. + + +```java +public interface RequestHandler { + + boolean canHandleRequest(Request req); + + int getPriority(); + + void handle(Request req); + + String name(); +} + +@Slf4j +public class OrcCommander implements RequestHandler { + @Override + public boolean canHandleRequest(Request req) { + return req.getRequestType() == RequestType.DEFEND_CASTLE; + } + + @Override + public int getPriority() { + return 2; + } + + @Override + public void handle(Request req) { + req.markHandled(); + LOGGER.info("{} handling request \"{}\"", name(), req); + } + + @Override + public String name() { + return "Orc commander"; + } +} + +// يتم تعريف OrcOfficer و OrcSoldier بطريقة مشابهة لـ OrcCommander + + +``` + +الملك أورك يعطي الأوامر ويشكل السلسلة. + + +```java +public class OrcKing { + + private List handlers; + + public OrcKing() { + buildChain(); + } + + private void buildChain() { + handlers = Arrays.asList(new OrcCommander(), new OrcOfficer(), new OrcSoldier()); + } + + public void makeRequest(Request req) { + handlers + .stream() + .sorted(Comparator.comparing(RequestHandler::getPriority)) + .filter(handler -> handler.canHandleRequest(req)) + .findFirst() + .ifPresent(handler -> handler.handle(req)); + } +} +``` + +سلسلة المسؤولية في العمل. + + +```java +var king=new OrcKing(); + king.makeRequest(new Request(RequestType.DEFEND_CASTLE,"defend castle")); + king.makeRequest(new Request(RequestType.TORTURE_PRISONER,"torture prisoner")); + king.makeRequest(new Request(RequestType.COLLECT_TAX,"collect tax")); +``` + +إخراج وحدة التحكم. + + +``` +Orc commander handling request "defend castle" +Orc officer handling request "torture prisoner" +Orc soldier handling request "collect tax" +``` + +## مخطط الفئات + +![alt text](./etc/chain-of-responsibility.urm.png "مخطط الفئات لسلسلة المسؤولية") + +## التطبيقية + +استخدم سلسلة المسؤولية عندما + +* يمكن لعدة كائنات معالجة الطلب، ولا يتم التعرف على المعالج مسبقًا. يجب تحديد المعالج تلقائيًا. +* ترغب في إرسال طلب إلى أحد الكائنات دون تحديد المستقبل بشكل صريح. +* يجب تحديد مجموعة الكائنات التي يمكنها معالجة الطلب ديناميكيًا. + +## الاستخدامات المعروفة + +* التفاعل مع الأحداث في إطارات واجهات المستخدم الرسومية حيث يمكن معالجة الحدث في عدة مستويات من تسلسل مكونات واجهة المستخدم. +* إطارات عمل الوسطاء حيث يمر الطلب عبر سلسلة من كائنات المعالجة. +* أنظمة السجلات حيث يمكن أن تمر الرسائل عبر سلسلة من المسجلين، مع إمكانية معالجتها بطرق مختلفة. +* [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29) +* [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html) +* [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-) + +## العواقب + +المزايا: + +* تقليل الترابط. لا يحتاج مُرسل الطلب إلى معرفة المعالج المحدد الذي سيعالج الطلب. +* مرونة أكبر في تخصيص المسؤوليات للكائنات. يمكن إضافة أو تغيير المسؤوليات لإدارة الطلب عن طريق تغيير أعضاء وترتيب السلسلة. +* يتيح تعيين معالج افتراضي إذا لم يكن هناك معالج محدد يمكنه معالجة الطلب. + +العيوب: + +* قد يكون من الصعب تصحيح الأخطاء وفهم التدفق، خاصة إذا كانت السلسلة طويلة ومعقدة. +* قد يبقى الطلب دون معالجة إذا كانت السلسلة لا تحتوي على معالج "التقاط الكل". +* قد تنشأ مشكلات في الأداء بسبب إمكانية مرور الطلب عبر عدة معالجات قبل العثور على المعالج المناسب، أو عدم العثور عليه على الإطلاق. + +## الأنماط ذات الصلة + +* [الأمر](https://java-design-patterns.com/patterns/command/): يمكن استخدامه لتغليف طلب ككائن، يمكن تمريره عبر السلسلة. +* [التركيب](https://java-design-patterns.com/patterns/composite/): غالبًا ما يتم تطبيق نمط سلسلة المسؤولية مع نمط التركيب. +* [الزخرفة](https://java-design-patterns.com/patterns/decorator/): يمكن ربط الزخارف بشكل مشابه للمسؤوليات في نمط سلسلة المسؤولية. + +## الاعتمادات + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Pattern-Oriented Software Architecture, Volume 1: A System of Patterns](https://amzn.to/3PAJUg5) +* [Refactoring to Patterns](https://amzn.to/3VOO4F5) +* [Pattern languages of program design 3](https://amzn.to/4a4NxTH) diff --git a/localization/ar/chain-of-responsibility/etc/chain-of-responsibility.urm.png b/localization/ar/chain-of-responsibility/etc/chain-of-responsibility.urm.png new file mode 100644 index 000000000000..af1bd105455b Binary files /dev/null and b/localization/ar/chain-of-responsibility/etc/chain-of-responsibility.urm.png differ diff --git a/localization/ar/client-session/README.md b/localization/ar/client-session/README.md new file mode 100644 index 000000000000..a6892e80b239 --- /dev/null +++ b/localization/ar/client-session/README.md @@ -0,0 +1,118 @@ +--- +title: Client Session +shortTitle: Client Session +category: Behavioral +language: ar +tags: + - Session management + - Web development +--- + +## أيضًا معروف باسم + +* جلسة المستخدم + +## الهدف + +يهدف نمط التصميم "جلسة العميل" إلى الحفاظ على حالة وبيانات المستخدم عبر طلبات متعددة ضمن تطبيق ويب، مما يضمن تجربة مستخدم مستمرة وشخصية. + +## الشرح + +مثال واقعي + +> ترغب في إنشاء تطبيق لإدارة البيانات يسمح للمستخدمين بإرسال طلبات إلى الخادم لتعديل وإجراء تغييرات على البيانات المخزنة على أجهزتهم. هذه الطلبات صغيرة والبيانات فردية لكل مستخدم، مما يلغي الحاجة إلى تنفيذ قاعدة بيانات واسعة النطاق. باستخدام نمط جلسة العميل، يمكن إدارة عدة طلبات في نفس الوقت، مع تحقيق توازن في تحميل العملاء عبر خوادم مختلفة بسهولة لأن الخوادم تظل بدون حالة. كما يتم القضاء على الحاجة إلى تخزين معرفات الجلسة على الخادم لأن العملاء يقدمون كل المعلومات التي يحتاجها الخادم لمعالجة طلباتهم. + +بإيجاز + +> بدلاً من تخزين معلومات عن العميل الحالي والمعلومات التي يتم الوصول إليها على الخادم، يتم الاحتفاظ بها فقط على جانب العميل. يجب على العميل إرسال بيانات الجلسة مع كل طلب إلى الخادم ويجب عليه إرسال حالة محدثة مرة أخرى إلى العميل، التي يتم تخزينها على جهاز العميل. لا يتعين على الخادم تخزين معلومات العميل. ([مرجع](https://dzone.com/articles/practical-php-patterns/practical-php-patterns-client)) + +**مثال برمجي** + +إليك كود مثال لوصف نمط جلسة العميل. في الكود التالي، نقوم أولاً بإنشاء مثيل للخادم. سيتم استخدام هذا المثيل بعد ذلك للحصول على كائنات الجلسة لعميلين. كما ترى في الكود التالي، يمكن استخدام كائن الجلسة لتخزين أي معلومات ذات صلة يحتاجها الخادم لمعالجة طلب العميل. سيتم تمرير هذه الكائنات مع كل طلب إلى الخادم. سيتضمن الطلب كائن الجلسة الذي يخزن التفاصيل ذات الصلة بالعميل مع البيانات المطلوبة لمعالجة الطلب. تساعد معلومات الجلسة في كل طلب الخادم في التعرف على العميل ومعالجة الطلب بناءً على ذلك. + + +```java +public class App { + + public static void main(String[] args) { + var server = new Server("localhost", 8080); + var session1 = server.getSession("Session1"); + var session2 = server.getSession("Session2"); + var request1 = new Request("Data1", session1); + var request2 = new Request("Data2", session2); + server.process(request1); + server.process(request2); + } +} + +@Data +@AllArgsConstructor +public class Session { + + /** + * Session id. + */ + private String id; + + /** + * Client name. + */ + private String clientName; + +} + +@Data +@AllArgsConstructor +public class Request { + + private String data; + + private Session session; + +} +``` + +## مخطط الهيكلية + +![alt text](./etc/session_state_pattern.png "نمط حالة الجلسة") + +## قابلية التطبيق + +استخدم نمط حالة الجلسة عندما: + +* التطبيقات الويب التي تتطلب مصادقة وتفويض المستخدم. +* التطبيقات التي تحتاج إلى تتبع أنشطة وتفضيلات المستخدم عبر طلبات أو زيارات متعددة. +* الأنظمة التي يحتاج فيها موارد الخادم إلى التحسين عن طريق تحميل إدارة الحالة إلى جانب العميل. + +## الاستخدامات المعروفة + +* مواقع التجارة الإلكترونية لتتبع محتويات سلة التسوق عبر الجلسات. +* المنصات عبر الإنترنت التي تقدم محتوى مخصص بناءً على تفضيلات وسجل المستخدم. +* تطبيقات الويب التي تتطلب تسجيل دخول المستخدم للوصول إلى المحتوى المخصص أو الآمن. + +## العواقب + +الفوائد: + +* تحسين أداء الخادم من خلال تقليل الحاجة لتخزين حالة المستخدم على الخادم. +* تحسين تجربة المستخدم من خلال المحتوى المخصص والتنقل السلس عبر أجزاء التطبيق المختلفة. +* مرونة في إدارة الجلسات من خلال عدة آليات تخزين على جانب العميل (مثل الكوكيز، Web Storage API). + +العيوب: + +* مخاطر محتملة للأمان إذا تم تخزين معلومات حساسة في جلسات العميل دون التشفير والتحقق المناسب. +* الاعتماد على قدرات وضبط العميل، مثل سياسات الكوكيز التي قد تختلف حسب المتصفح وإعدادات المستخدم. +* زيادة التعقيد في منطق إدارة الجلسات، خاصة في إدارة انتهاء الصلاحية، التجديد ومزامنة الجلسات عبر الأجهزة أو النوافذ المتعددة. + +## الأنماط ذات الصلة + +* جلسة الخادم: غالباً ما يُستخدم جنباً إلى جنب مع نمط جلسة العميل لتوفير توازن بين كفاءة جانب العميل والتحكم في جانب الخادم. +* [سينجلتون](https://java-design-patterns.com/patterns/singleton/): ضمان وجود مثيل واحد فقط من جلسة المستخدم في التطبيق بأكمله. +* [حالة](https://java-design-patterns.com/patterns/state/): إدارة تحولات الحالة في الجلسة مثل الحالات المصادق عليها، الضيف أو المنتهية. + +## الفضل + +* [DZone - Practical PHP patterns](https://dzone.com/articles/practical-php-patterns/practical-php-patterns-client) +* [نمط حالة جلسة العميل - Ram N Java](https://www.youtube.com/watch?v=ycOSj9g41pc) +* [Java الاحترافي لتطبيقات الويب](https://amzn.to/4aazY59) +* [تأمين تطبيقات الويب باستخدام Spring Security](https://amzn.to/3PCCEA1) diff --git a/localization/ar/client-session/etc/session_state_pattern.png b/localization/ar/client-session/etc/session_state_pattern.png new file mode 100644 index 000000000000..f1e23be95766 Binary files /dev/null and b/localization/ar/client-session/etc/session_state_pattern.png differ diff --git a/localization/ar/collecting-parameter/README.md b/localization/ar/collecting-parameter/README.md new file mode 100644 index 000000000000..c799bb0223de --- /dev/null +++ b/localization/ar/collecting-parameter/README.md @@ -0,0 +1,222 @@ +--- +title: Collecting Parameter +shortTitle: Collecting Parameter +category: Behavioral +language: ar +tag: + - Accumulation + - Generic +--- + +## أيضًا يُعرف بـ + +* جامع +* مُجمّع + +## الهدف + +يهدف إلى تبسيط الطرق التي تجمع المعلومات من خلال تمرير كائن جمع واحد عبر عدة استدعاءات للطرق، مما يسمح لها بإضافة النتائج إلى هذه المجموعة بدلاً من أن يقوم كل طريقة بإنشاء مجموعة خاصة بها. + +## الشرح + +### مثال من العالم الحقيقي + +داخل مبنى تجاري كبير، توجد طابعات مُشتركة تعد مجموعة من جميع وظائف الطباعة المعلقة حاليًا. تحتوي الطوابق المختلفة على طرز مختلفة من الطابعات، ولكل منها سياسة طباعة مختلفة. يجب علينا بناء برنامج يمكنه إضافة مهام الطباعة المناسبة بشكل مستمر إلى مجموعة تسمى *معامل الجمع*. + +### ببساطة + +بدلاً من وجود دالة ضخمة تحتوي على العديد من السياسات لجمع المعلومات في متغير، يمكننا إنشاء العديد من الدوال الصغيرة التي تأخذ كل معلم، وتضيف معلومات جديدة. يمكننا تمرير المعامل إلى كل من هذه الدوال الصغيرة وفي النهاية، سيكون لدينا ما أردناه في الأصل. في هذه المرة، يكون الكود أنظف وأسهل في الفهم. نظرًا لأن الدالة الكبيرة قد تم تقسيمها، فإن الكود أيضًا أسهل في التعديل حيث يتم تحديد التغييرات في الدوال الصغيرة. + +### تقول ويكيبيديا + +في اصطلاح المعاملات الجامعية، يتم تمرير مجموعة (قائمة، خريطة، إلخ) بشكل متكرر كمعامل إلى دالة تضيف العناصر إلى المجموعة. + +### مثال برمجي + +بتشفير مثالنا السابق، يمكننا استخدام مجموعة `النتيجة` كمعامل جامع. يتم تنفيذ القيود التالية: + +- إذا كان ورق A4 ملونًا، يجب أن يكون أيضًا من جهة واحدة. يتم قبول جميع الأوراق غير الملونة الأخرى. +- لا يجب أن يكون ورق A3 ملونًا ويجب أن يكون من جهة واحدة. +- يجب أن يكون ورق A2 من صفحة واحدة، من جهة واحدة وغير ملون. + + +```java +package com.iluwatar.collectingparameter; + +import java.util.LinkedList; +import java.util.Queue; + +public class App { + static PrinterQueue printerQueue = PrinterQueue.getInstance(); + + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + /* + Initialising the printer queue with jobs + */ + printerQueue.addPrinterItem(new PrinterItem(PaperSizes.A4, 5, false, false)); + printerQueue.addPrinterItem(new PrinterItem(PaperSizes.A3, 2, false, false)); + printerQueue.addPrinterItem(new PrinterItem(PaperSizes.A2, 5, false, false)); + + /* + This variable is the collecting parameter. + */ + var result = new LinkedList(); + + /* + * Using numerous sub-methods to collaboratively add information to the result collecting parameter + */ + addA4Papers(result); + addA3Papers(result); + addA2Papers(result); + } +} +``` + +نستخدم الطرق `addA4Paper` و `addA3Paper` و `addA2Paper` لملء معامل الجمع `النتيجة` بالوظائف المناسبة للطباعة وفقًا للسياسة الموصوفة سابقًا. يتم ترميز السياسات الثلاث كما يلي: + + +```java +public class App { + static PrinterQueue printerQueue = PrinterQueue.getInstance(); + + /** + * Adds A4 document jobs to the collecting parameter according to some policy that can be whatever the client + * (the print center) wants. + * + * @param printerItemsCollection the collecting parameter + */ + public static void addA4Papers(Queue printerItemsCollection) { + /* + Iterate through the printer queue, and add A4 papers according to the correct policy to the collecting parameter, + which is 'printerItemsCollection' in this case. + */ + for (PrinterItem nextItem : printerQueue.getPrinterQueue()) { + if (nextItem.paperSize.equals(PaperSizes.A4)) { + var isColouredAndSingleSided = + nextItem.isColour && !nextItem.isDoubleSided; + if (isColouredAndSingleSided) { + printerItemsCollection.add(nextItem); + } else if (!nextItem.isColour) { + printerItemsCollection.add(nextItem); + } + } + } + } + + /** + * Adds A3 document jobs to the collecting parameter according to some policy that can be whatever the client + * (the print center) wants. The code is similar to the 'addA4Papers' method. The code can be changed to accommodate + * the wants of the client. + * + * @param printerItemsCollection the collecting parameter + */ + public static void addA3Papers(Queue printerItemsCollection) { + for (PrinterItem nextItem : printerQueue.getPrinterQueue()) { + if (nextItem.paperSize.equals(PaperSizes.A3)) { + + // Encoding the policy into a Boolean: the A3 paper cannot be coloured and double-sided at the same time + var isNotColouredAndSingleSided = + !nextItem.isColour && !nextItem.isDoubleSided; + if (isNotColouredAndSingleSided) { + printerItemsCollection.add(nextItem); + } + } + } + } + + /** + * Adds A2 document jobs to the collecting parameter according to some policy that can be whatever the client + * (the print center) wants. The code is similar to the 'addA4Papers' method. The code can be changed to accommodate + * the wants of the client. + * + * @param printerItemsCollection the collecting parameter + */ + public static void addA2Papers(Queue printerItemsCollection) { + for (PrinterItem nextItem : printerQueue.getPrinterQueue()) { + if (nextItem.paperSize.equals(PaperSizes.A2)) { + + // Encoding the policy into a Boolean: the A2 paper must be single page, single-sided, and non-coloured. + var isNotColouredSingleSidedAndOnePage = + nextItem.pageCount == 1 && + !nextItem.isDoubleSided + && !nextItem.isColour; + if (isNotColouredSingleSidedAndOnePage) { + printerItemsCollection.add(nextItem); + } + } + } + } +} +``` + +كل طريقة تأخذ كمعامل معلمة جمع. بعد ذلك، تضيف العناصر، المأخوذة من متغير عالمي، إلى هذه المعلمة إذا كانت كل عنصر يفي بمعيار معين. يمكن أن تحتوي هذه الطرق على السياسة التي يرغب فيها العميل. + +في هذا المثال البرمجي، يتم إضافة ثلاث مهام طباعة إلى الطابور. فقط أول مهمتين للطباعة يجب إضافتهما إلى معلمة الجمع وفقًا للسياسة. العناصر في متغير `النتيجة` بعد التنفيذ هي: + +| حجم الورق | عدد الصفحات | مزدوج الوجه | ملون | +|-----------|-------------|-------------|------| +| A4 | 5 | false | false | +| A3 | 2 | false | false | + +وهذا هو ما توقعناه. + +## مخطط الفئات + +![alt text](./etc/collecting-parameter.urm.png "معامل الجمع") + +## قابلية التطبيق + +استخدم نمط التصميم جمع المعاملات عندما: + +- عندما تنتج عدة طرق مجموعة من النتائج وتريد إضافة هذه النتائج بطريقة موحدة. +- في السيناريوهات حيث يمكن أن يحسن تقليل عدد المجموعات التي يتم إنشاؤها بواسطة الطرق من كفاءة الذاكرة والأداء. +- عند إعادة هيكلة الطرق الكبيرة التي تقوم بعدة مهام، بما في ذلك جمع النتائج من عمليات متعددة. + +## الدروس التعليمية + +الدروس التعليمية لهذه الطريقة موجودة في: + +- [Refactoring To Patterns](http://www.tarrani.net/RefactoringToPatterns.pdf) بواسطة Joshua Kerivsky +- [Smalltalk Best Practice Patterns](https://ptgmedia.pearsoncmg.com/images/9780134769042/samplepages/013476904X.pdf) بواسطة Kent Beck + +## الاستخدامات المعروفة + +يوضح Joshua Kerivsky مثالًا واقعيًا في كتابه 'Refactoring to Patterns'. يقدم مثالًا لاستخدام نمط التصميم "جمع المعاملات" لإنشاء طريقة `toString()` لشجرة XML. بدون استخدام هذا النمط، سيحتاج ذلك إلى وظيفة ضخمة تحتوي على شروط ودمج النصوص مما سيزيد من صعوبة قراءة الشيفرة. يمكن تقسيم مثل هذه الطريقة إلى طرق أصغر، حيث يضيف كل منها مجموعة خاصة من المعلومات إلى معلمة الجمع. انظر إلى هذا في [Refactoring To Patterns](http://www.tarrani.net/RefactoringToPatterns.pdf). + +أمثلة أخرى هي: + +- إضافة رسائل الخطأ أو فشل التحقق في عملية تحقق معقدة. +- جمع العناصر أو المعلومات أثناء التنقل في هيكل بيانات معقد. +- إعادة هيكلة الوظائف المعقدة للتقارير حيث يتم إنشاء أجزاء متعددة من التقرير باستخدام طرق مختلفة. + +## العواقب + +المزايا: + +- يقلل من تكرار الشيفرة من خلال تجميع معالجة المجموعات في مكان واحد. +- يحسن الوضوح وقابلية الصيانة من خلال توضيح مكان وكيفية جمع النتائج. +- يحسن الأداء عن طريق تقليل إنشاء وإدارة كائنات جمع متعددة. + +العيوب: + +- يزيد من الترابط بين المنادي والطرق المنادى عليها، حيث يجب أن يتفقوا على المجموعة المستخدمة. +- قد يقدم آثار جانبية في الطرق إذا لم تتم إدارتها بعناية، حيث لم تعد الطرق مستقلة في إدارة النتائج. + +## الأنماط ذات الصلة + +- [Composite](https://java-design-patterns.com/patterns/composite/): يمكن استخدامه مع جمع المعاملات عند العمل مع الهياكل الهرمية، مما يسمح بجمع النتائج عبر هيكل مركب. +- [Visitor](https://java-design-patterns.com/patterns/visitor/): يستخدم غالبًا معًا، حيث يتولى Visitor المرور وإجراء العمليات في هيكل، بينما يقوم جمع المعاملات بتراكم النتائج. +- [Command](https://java-design-patterns.com/patterns/command/): يمكن للأوامر استخدام معلمة الجمع لإضافة نتائج عدة عمليات يتم تنفيذها بواسطة كائنات الأمر. + +## الشكر + +- [Refactoring To Patterns](http://www.tarrani.net/RefactoringToPatterns.pdf) بواسطة Joshua Kerivsky +- [Smalltalk Best Practice Patterns](https://ptgmedia.pearsoncmg.com/images/9780134769042/samplepages/013476904X.pdf) بواسطة Kent Beck +- [Wiki](https://wiki.c2.com/?CollectingParameter) +- [Refactoring: Improving the Design of Existing Code](https://amzn.to/3TVEgaB) +- [Clean Code: A Handbook of Agile Software Craftsmanship](https://amzn.to/4aApLP0) diff --git a/localization/ar/collecting-parameter/etc/collecting-parameter.urm.png b/localization/ar/collecting-parameter/etc/collecting-parameter.urm.png new file mode 100644 index 000000000000..785d6ecc2da1 Binary files /dev/null and b/localization/ar/collecting-parameter/etc/collecting-parameter.urm.png differ diff --git a/localization/ar/command/README.md b/localization/ar/command/README.md new file mode 100644 index 000000000000..af20644ab502 --- /dev/null +++ b/localization/ar/command/README.md @@ -0,0 +1,245 @@ +--- +title: Command +shortTitle: Command +category: Behavioral +language: ar +tag: + - Gang of Four +--- + +## أيضًا يعرف بـ + +* إجراء +* معاملة + +## الهدف + +يُغلف نمط التصميم Command الطلب ككائن، مما يسمح بتمرير العملاء مع قوائم الانتظار، الطلبات، والعمليات. كما يدعم أيضًا التراجع عن العمليات. + +## الشرح + +### مثال واقعي + +> يوجد ساحر يلقي تعويذات على عفريت. يتم تنفيذ التعويذات على العفريت واحدة تلو الأخرى. التعويذة الأولى تصغر العفريت والتعويذة الثانية تجعله غير مرئي. بعد ذلك، يقوم الساحر بالتراجع عن التعويذات واحدة تلو الأخرى. كل تعويذة هي كائن أمر يمكن التراجع عنها. + +### بكلمات بسيطة: + +> تخزين الطلبات ككائنات أمر يسمح بتنفيذ الإجراء أو التراجع عنه في وقت لاحق. + +### تقول ويكيبيديا: + +> في البرمجة الكائنية التوجه، نمط الأمر هو نمط تصميم سلوكي حيث يتم استخدام كائن لتغليف كافة المعلومات اللازمة لتنفيذ إجراء أو تحفيز حدث في وقت لاحق. + +### مثال برمجي + +إليك الكود البرمجي مع الساحر `Wizard` والعفريت `Goblin`. دعونا نبدأ بفئة الساحر `Wizard`. + + +```java + +@Slf4j +public class Wizard { + + private final Deque undoStack = new LinkedList<>(); + private final Deque 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"; + } +} +``` + +### التالي، لدينا العفريت `Goblin` الذي هو الهدف `Target` للتعويذات. + + +```java + +@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); + } +} +``` + +### أخيرًا، لدينا الساحر في الدالة الرئيسية وهو يلقي التعويذات. + + +```java +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(); +``` + +### هذا هو المثال قيد التنفيذ. + + +```java +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(); +``` + +### إليك مخرجات البرنامج: + + +```java +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](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html) +* [org.junit.runners.model.Statement](https://github.com/junit-team/junit4/blob/master/src/main/java/org/junit/runners/model/Statement.java) +* [Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki) +* [javax.swing.Action](http://docs.oracle.com/javase/8/docs/api/javax/swing/Action.html) + +## العواقب + +المزايا: + +* يفصل الكائن الذي يستدعي العملية عن الكائن الذي يعرف كيفية تنفيذها. +* من السهل إضافة أوامر جديدة، لأنه لا يتعين عليك تغيير الفئات الموجودة. +* يمكنك تجميع مجموعة من الأوامر في أمر مركب. + +العيوب: + +* يزيد عدد الفئات لكل أمر فردي. +* قد يعقد التصميم عند إضافة طبقات متعددة بين المرسلين والمستلمين. + +## الأنماط ذات الصلة + +* [Composite](https://java-design-patterns.com/patterns/composite/): يمكن تجميع الأوامر باستخدام نمط المركب لإنشاء أوامر كبيرة. +* [Memento](https://java-design-patterns.com/patterns/memento/): يمكن استخدامه لتنفيذ آليات التراجع. +* [Observer](https://java-design-patterns.com/patterns/observer/): يمكن ملاحظة النمط لتغييرات التي تفعّل الأوامر. + +## المصادر + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) +* [Pattern-Oriented Software Architecture, Volume 1: A System of Patterns](https://amzn.to/3PFUqSY) diff --git a/localization/ar/command/etc/command.png b/localization/ar/command/etc/command.png new file mode 100644 index 000000000000..0f026464ecc4 Binary files /dev/null and b/localization/ar/command/etc/command.png differ diff --git a/localization/ar/commander/README.md b/localization/ar/commander/README.md new file mode 100644 index 000000000000..2cb0b72e17f1 --- /dev/null +++ b/localization/ar/commander/README.md @@ -0,0 +1,136 @@ +--- +title: Commander +shortTitle: Commander +category: Behavioral +language: ar +tag: + - Cloud distributed + - Microservices + - Transactions +--- + +## أيضا يُعرف باسم + +* منسق المعاملات الموزعة +* منسق المعاملات + +## الهدف + +الهدف من نمط "المنسق" في سياق المعاملات الموزعة هو إدارة وتنسيق المعاملات المعقدة عبر العديد من المكونات أو الخدمات الموزعة، مما يضمن التناسق والنزاهة للمعاملة العالمية. يقوم بتغليف أوامر المعاملات ومنطق التنسيق، مما يسهل تنفيذ بروتوكولات المعاملات الموزعة مثل الالتزام ذو المرحلتين أو ساغا. + +## الشرح + +مثال حقيقي + +> تخيل أنك تنظم مهرجان موسيقي دولي كبير، حيث من المقرر أن تؤدي عدة فرق من جميع أنحاء العالم. وصول كل فرقة، واختبار الصوت، والأداء، كل منها يعد معاملة فردية في نظام موزع. يتصرف منظم المهرجان كـ "منسق"، منسقًا هذه المعاملات لضمان أنه إذا تأخر طيران إحدى الفرق (مثل فشل المعاملة)، فهناك خطة احتياطية مثل إعادة جدولة أو تبادل الفترات الزمنية مع فرقة أخرى (إجراءات تعويضية)، للحفاظ على سير البرنامج العام. تعكس هذه الإعدادات نمط المنسق في المعاملات الموزعة، حيث يجب تنسيق العديد من المكونات لتحقيق نتيجة مرضية رغم الفشل الفردي. + +بكلمات بسيطة + +> يقوم نمط "المنسق" بتحويل الطلب إلى كائن مستقل، مما يسمح بمعلمة الأوامر، ووضع الإجراءات في طابور، وتنفيذ عمليات التراجع. + +**مثال برمجي** + +إدارة المعاملات عبر خدمات مختلفة في نظام موزع، مثل منصة للتجارة الإلكترونية تحتوي على خدمات منفصلة للدفع والشحن، تتطلب تنسيقًا دقيقًا لتجنب المشكلات. عندما يقدم المستخدم طلبًا ولكن خدمة واحدة (مثل الدفع) غير متوفرة بينما الخدمة الأخرى (مثل الشحن) جاهزة، نحتاج إلى حل قوي للتعامل مع هذا التفاوت. + +إحدى الاستراتيجيات لحل هذه المشكلة هي استخدام مكون منسق لتنظيم العملية. في البداية، تتم معالجة الطلب من قبل الخدمة المتاحة (الشحن في هذه الحالة). ثم يحاول المنسق مزامنة الطلب مع الخدمة غير المتوفرة في ذلك الوقت (الدفع) من خلال تخزين تفاصيل الطلب في قاعدة بيانات أو وضعه في طابور للمعالجة في المستقبل. يجب أن يأخذ هذا النظام في الحسبان الفشل المحتمل عند إضافة الطلبات إلى الطابور. + +يحاول المنسق بشكل متكرر معالجة الطلبات في الطابور لضمان أن تعكس جميع الخدمات أخيرًا نفس بيانات المعاملة. يتضمن هذا العملية ضمان التكرارية، مما يعني أنه حتى إذا تم إجراء نفس طلب مزامنة الطلبات عدة مرات، فسيتم تنفيذه مرة واحدة فقط، مما يمنع المعاملات المكررة. الهدف هو تحقيق التناسق النهائي بين الخدمات، حيث تتزامن جميع الأنظمة بمرور الوقت على الرغم من الفشل أو التأخير الأولي. + +في الكود المقدم، يُستخدم نمط المنسق لإدارة المعاملات الموزعة عبر العديد من الخدمات (خدمة الدفع، خدمة الشحن، خدمة الرسائل، إدارة الموظفين). كل خدمة تحتوي على قاعدة بيانات خاصة بها ويمكن أن تُطلق استثناءات لمحاكاة الفشل. + +فئة المنسق هي الجزء المركزي من هذا النمط. تأخذ الفئة المنسق مثيلات لجميع الخدمات وقواعد بياناتها، جنبًا إلى جنب مع بعض معلمات التكوين. تُستخدم دالة placeOrder في فئة المنسق لتنفيذ الطلب، مما يتطلب التفاعل مع جميع الخدمات. + + +```java +public class Commander { + // ... constructor and other methods ... + + public void placeOrder(Order order) { + // ... implementation ... + } +} +``` + +تمثل الفئات "المستخدم" و "الطلب" مستخدمًا وطلبًا على التوالي. يتم إجراء الطلب بواسطة المستخدم. + + +```java +public class User { + // ... constructor and other methods ... +} + +public class Order { + // ... constructor and other methods ... +} +``` + +كل خدمة (على سبيل المثال، خدمة الدفع، خدمة الشحن، خدمة الرسائل، إدارة الموظفين) لديها قاعدة بيانات خاصة بها ويمكن أن تُطلق استثناءات لمحاكاة الأعطال. على سبيل المثال، قد تقوم خدمة الدفع بإطلاق استثناء DatabaseUnavailableException إذا كانت قاعدة بياناتها غير متاحة. + + +```java +public class PaymentService { + // ... constructor and other methods ... +} +``` + +تمثل الفئات DatabaseUnavailableException و ItemUnavailableException و ShippingNotPossibleException أنواعًا مختلفة من الاستثناءات التي قد تحدث. + + +```java +public class DatabaseUnavailableException extends Exception { + // ... constructor and other methods ... +} + +public class ItemUnavailableException extends Exception { + // ... constructor and other methods ... +} + +public class ShippingNotPossibleException extends Exception { + // ... constructor and other methods ... +} +``` + +في الطريقة الرئيسية لكل فئة (AppQueueFailCases و AppShippingFailCases)، يتم محاكاة سيناريوهات مختلفة عن طريق إنشاء مثيلات من فئة Commander مع تكوينات مختلفة واستدعاء طريقة placeOrder. + +## مخطط الفئات + +![alt text](./etc/commander.urm.png "مخطط فئة Commander") + +## قابلية التطبيق + +استخدم نمط Commander للمعاملات الموزعة عندما: + +* تحتاج إلى ضمان اتساق البيانات بين الخدمات الموزعة في حالة حدوث فشل جزئي في النظام. +* تشمل المعاملات عدة خدمات ميكروسيرفيس أو مكونات موزعة تتطلب commit أو rollback منسق. +* تقوم بتنفيذ معاملات طويلة الأجل تتطلب إجراءات تعويضية للإلغاء. + +## الاستخدامات المعروفة + +* بروتوكولات Two-Phase Commit (2PC): التنسيق بين commit أو rollback عبر قواعد البيانات أو الخدمات الموزعة. +* تنفيذات نمط Saga: إدارة عمليات الأعمال طويلة الأجل التي تشمل العديد من الميكروسيرفيس، مع وجود إجراء تعويضي لكل خطوة للإلغاء. +* المعاملات الموزعة في بنية الميكروسيرفيس: تنسيق العمليات المعقدة بين الميكروسيرفيس مع الحفاظ على تكامل البيانات واتساقها. + +## العواقب + +الفوائد: + +* يوفر آلية واضحة لإدارة المعاملات الموزعة المعقدة، مما يحسن موثوقية النظام. +* يسمح بتنفيذ المعاملات التعويضية، وهي ضرورية للحفاظ على التناسق في المعاملات طويلة الأجل. +* يسهل دمج الأنظمة المتجانسة في سياق المعاملات. + +العيوب: + +* يزيد من التعقيد، خاصة في حالات الفشل، بسبب الحاجة إلى آليات التراجع المنسقة. +* قد يؤثر على الأداء بسبب الحمل الزائد للتنسيق وفحوصات التناسق. +* قد تؤدي التنفيذات المعتمدة على Saga إلى زيادة التعقيد في فهم سير العملية التجارية العامة. + +## الأنماط المرتبطة + +[Nمط Saga](https://java-design-patterns.com/patterns/saga/): غالبًا ما يتم مناقشته مع نمط Commander للمعاملات الموزعة، مع التركيز على المعاملات طويلة الأجل مع إجراءات تعويضية. + +## الشكر + +* [المعاملات الموزعة: جبال الجليد في الميكروسيرفيس](https://www.grahamlea.com/2016/08/distributed-transactions-microservices-icebergs/) +* [أنماط الميكروسيرفيس: مع أمثلة في جافا](https://amzn.to/4axjnYW) +* [تصميم التطبيقات المعتمدة على البيانات: الأفكار الكبيرة وراء الأنظمة القابلة للاعتماد، القابلة للتوسع، والقابلة للصيانة](https://amzn.to/4axHwOV) +* [أنماط تكامل المؤسسات: تصميم وبناء ونشر حلول الرسائل](https://amzn.to/4aATcRe) diff --git a/localization/ar/commander/etc/commander.urm.png b/localization/ar/commander/etc/commander.urm.png new file mode 100644 index 000000000000..6b5ebba75bd6 Binary files /dev/null and b/localization/ar/commander/etc/commander.urm.png differ diff --git a/localization/ar/composite-entity/README.md b/localization/ar/composite-entity/README.md new file mode 100644 index 000000000000..0e04ae3efe03 --- /dev/null +++ b/localization/ar/composite-entity/README.md @@ -0,0 +1,159 @@ +--- +title: Composite Entity +shortTitle: Composite Entity +category: Structural +language: ar +tag: + - Client-server + - Data access + - Enterprise patterns +--- + +## أيضا يُعرف بـ + +* الكيان ذو الحبيبات الخشنة + +## الهدف + +هدف نمط التصميم **الكيان المركب** هو إدارة مجموعة من الكائنات المستمرة المترابطة كما لو كانت كيانًا واحدًا. يتم استخدامه عادة في سياق **Enterprise JavaBeans (EJB)** وأطر العمل التجارية المماثلة لتمثيل الهياكل البيانية للبيانات ضمن نماذج الأعمال، مما يتيح للعملاء التعامل معها كوحدة واحدة. + +## الشرح + +مثال واقعي + +> في وحدة التحكم، قد يكون هناك العديد من الواجهات التي تحتاج إلى إدارة ومراقبة. باستخدام نمط الكيان المركب، يمكن دمج الكائنات المعتمدة مثل الرسائل والإشارات والسيطرة عليها باستخدام كائن واحد. + +بكلمات بسيطة + +> نمط الكيان المركب يسمح بتمثيل وإدارة مجموعة من الكائنات المرتبطة من خلال كائن موحد. + +**مثال برمجي** + +نحتاج إلى حل عام للمشكلة. لذلك، سنقدم نمطًا عامًا للكيان المركب. + + +```java +public abstract class DependentObject { + + T data; + + public void setData(T message) { + this.data = message; + } + + public T getData() { + return data; + } +} + +public abstract class CoarseGrainedObject { + + DependentObject[] dependentObjects; + + public void setData(T... data) { + IntStream.range(0, data.length).forEach(i -> dependentObjects[i].setData(data[i])); + } + + public T[] getData() { + return (T[]) Arrays.stream(dependentObjects).map(DependentObject::getData).toArray(); + } +} + +``` + +الكائن المركب المتخصص `consola` يرث من هذه الفئة الأساسية بالطريقة التالية. + + +```java +public class MessageDependentObject extends DependentObject { + +} + +public class SignalDependentObject extends DependentObject { + +} + +public class ConsoleCoarseGrainedObject extends CoarseGrainedObject { + + @Override + public String[] getData() { + super.getData(); + return new String[] { + dependentObjects[0].getData(), dependentObjects[1].getData() + }; + } + + public void init() { + dependentObjects = new DependentObject[] { + new MessageDependentObject(), new SignalDependentObject()}; + } +} + +public class CompositeEntity { + + private final ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject(); + + public void setData(String message, String signal) { + console.setData(message, signal); + } + + public String[] getData() { + return console.getData(); + } +} +``` + +إدارة الآن تخصيص كائنات الرسالة والإشارة مع الكائن المركب `consola`. + + +```java +var console=new CompositeEntity(); + console.init(); + console.setData("No Danger","Green Light"); + Arrays.stream(console.getData()).forEach(LOGGER::info); + console.setData("Danger","Red Light"); + Arrays.stream(console.getData()).forEach(LOGGER::info); +``` + +## مخطط الفئات + +![alt text](./etc/composite_entity.urm.png "نمط الكائن المركب") + +## القابلية للتطبيق + +* مفيد في التطبيقات التجارية حيث تكون الكائنات التجارية معقدة وتنطوي على عدة كائنات مترابطة. +* مثالي للسيناريوهات التي يحتاج فيها العملاء للعمل مع واجهة موحدة لمجموعة من الكائنات بدلاً من الكائنات الفردية. +* قابل للتطبيق في الأنظمة التي تتطلب عرضًا مبسطًا لنموذج بيانات معقد للعملاء أو الخدمات الخارجية. + +## الاستخدامات المعروفة + +* التطبيقات التجارية ذات النماذج التجارية المعقدة، وخاصة تلك التي تستخدم EJB أو أطر عمل تجارية مشابهة. +* الأنظمة التي تتطلب تجريدًا فوق مخططات قواعد بيانات معقدة لتبسيط التفاعلات مع العملاء. +* التطبيقات التي تحتاج إلى تعزيز التناسق أو المعاملات عبر عدة كائنات في كائن تجاري واحد. + +## العواقب + +الفوائد: + +* يبسط تفاعلات العميل مع النماذج الكائنية المعقدة من خلال توفير واجهة موحدة. +* يعزز إعادة الاستخدام والصيانة في طبقة الأعمال عن طريق فصل كود العميل عن المكونات الداخلية المعقدة للكائنات التجارية. +* يسهل إدارة المعاملات وتطبيق التناسق في مجموعة من الكائنات المترابطة. + +السلبيات: + +* قد يقدم مستوى من الاستدلال الذي قد يؤثر على الأداء. +* قد يؤدي إلى واجهات ذات حبوب خشنة جدًا قد لا تكون مرنة لجميع احتياجات العملاء. +* يتطلب تصميمًا دقيقًا لتجنب الكائنات المركبة المتضخمة التي يصعب إدارتها. + +## الأنماط ذات الصلة + +* [الزخرفة](https://java-design-patterns.com/patterns/decorator/): لإضافة سلوك ديناميكي للكائنات الفردية داخل الكائن المركب دون التأثير على الهيكل. +* [الواجهة](https://java-design-patterns.com/patterns/facade/): يوفر واجهة مبسطة لنظام فرعي معقد، بشكل مشابه لكيفية تبسيط الكائن المركب الوصول إلى مجموعة من الكائنات. +* [الوزن الخفيف](https://java-design-patterns.com/patterns/flyweight/): مفيد لإدارة الكائنات المشتركة داخل الكائن المركب لتقليل بصمة الذاكرة. + +## الاعتمادات + +* [نمط الكائن المركب في ويكيبيديا](https://en.wikipedia.org/wiki/Composite_entity_pattern) +* [أفضل الممارسات واستراتيجيات التصميم في الأنماط الأساسية لـ J2EE](https://amzn.to/4cAbDap) +* [أنماط المؤسسة و MDA: بناء البرمجيات الأفضل باستخدام أنماط الأركيتايب و UML](https://amzn.to/49mslqS) +* [أنماط بنية التطبيقات المؤسسية](https://amzn.to/3xjKdpe) diff --git a/localization/ar/composite-entity/etc/composite_entity.urm.png b/localization/ar/composite-entity/etc/composite_entity.urm.png new file mode 100644 index 000000000000..d6c29a718837 Binary files /dev/null and b/localization/ar/composite-entity/etc/composite_entity.urm.png differ diff --git a/localization/ar/composite-view/README.md b/localization/ar/composite-view/README.md new file mode 100644 index 000000000000..dcd543c43a2f --- /dev/null +++ b/localization/ar/composite-view/README.md @@ -0,0 +1,353 @@ +--- +title: Composite View +shortTitle: Composite View +category: Structural +language: ar +tag: + - Enterprise patterns + - Presentation +--- + +## الغرض + +الهدف الرئيسي من نمط التصميم "عرض مركب" هو تكوين الكائنات في هياكل شجرية لتمثيل الهيراركية جزء-كامل. هذا يتيح للعملاء التعامل مع الكائنات الفردية وتركيبات الكائنات بشكل موحد، مما يبسط إدارة الهياكل المعقدة. + +## التفسير + +مثال من العالم الحقيقي + +> موقع إخباري يريد عرض التاريخ الحالي والأخبار لعدة مستخدمين بناءً على تفضيلات كل مستخدم. سيستبدل الموقع في مكونات تغذية الأخبار المختلفة حسب اهتمامات المستخدم، مع الأخبار المحلية كافتراضي. + +بإيجاز + +> نمط العرض المركب يتكون من عرض رئيسي مكون من عروض فرعية أصغر. يعتمد تصميم هذا العرض المركب على قالب. ثم يقرر مدير العرض أي العروض الفرعية يجب تضمينها في هذا القالب. + +تقول ويكيبيديا + +> العروض المركبة التي تتكون من العديد من العروض الفرعية الذرية. يمكن تضمين كل مكون من القالب ديناميكيًا في المجموعة ويمكن إدارة تصميم الصفحة بشكل مستقل عن المحتوى. يتيح هذا الحل إنشاء عرض مركب استنادًا إلى تضمين واستبدال أجزاء قابلة لإعادة الاستخدام من القوالب الديناميكية والثابتة. يعزز التصميم المعياري من خلال تشجيع إعادة استخدام أجزاء الذرة من العرض. + +**مثال برمجي** + +نظرًا لأن هذا نمط تطوير ويب، فإن الخادم مطلوب لعرضه. يستخدم هذا المثال Tomcat 10.0.13 لتشغيل السيرفلت، ولن يعمل هذا المثال البرمجي إلا مع Tomcat 10+. + +أولاً، يوجد `AppServlet` الذي هو `HttpServlet` يعمل في Tomcat 10+. + + +```java +public class AppServlet extends HttpServlet { + private String msgPartOne = "

This Server Doesn't Support"; + private String msgPartTwo = "Requests

\n" + + "

Use a GET request with boolean values for the following parameters

\n" + + "

'name'

\n

'bus'

\n

'sports'

\n

'sci'

\n

'world'

"; + + private String destination = "newsDisplay.jsp"; + + public AppServlet() { + + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + RequestDispatcher requestDispatcher = req.getRequestDispatcher(destination); + ClientPropertiesBean reqParams = new ClientPropertiesBean(req); + req.setAttribute("properties", reqParams); + requestDispatcher.forward(req, resp); + } + + @Override + public void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/html"); + PrintWriter out = resp.getWriter(); + out.println(msgPartOne + " Post " + msgPartTwo); + + } + + @Override + public void doDelete(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/html"); + PrintWriter out = resp.getWriter(); + out.println(msgPartOne + " Delete " + msgPartTwo); + + } + + @Override + public void doPut(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/html"); + PrintWriter out = resp.getWriter(); + out.println(msgPartOne + " Put " + msgPartTwo); + + } +} + +``` + +هذا السيرفلت لا يشكل جزءًا من النمط، ويقوم ببساطة بإعادة توجيه طلبات GET إلى JSP الصحيح. الطلبات PUT و POST و DELETE غير مدعومة وستعرض ببساطة رسالة خطأ. + +إدارة العرض في هذا المثال تتم من خلال فئة javabean: `ClientPropertiesBean`، التي تخزن تفضيلات المستخدم. + + +```java +public class ClientPropertiesBean implements Serializable { + + private static final String WORLD_PARAM = "world"; + private static final String SCIENCE_PARAM = "sci"; + private static final String SPORTS_PARAM = "sport"; + private static final String BUSINESS_PARAM = "bus"; + private static final String NAME_PARAM = "name"; + + private static final String DEFAULT_NAME = "DEFAULT_NAME"; + private boolean worldNewsInterest; + private boolean sportsInterest; + private boolean businessInterest; + private boolean scienceNewsInterest; + private String name; + + public ClientPropertiesBean() { + worldNewsInterest = true; + sportsInterest = true; + businessInterest = true; + scienceNewsInterest = true; + name = DEFAULT_NAME; + + } + + public ClientPropertiesBean(HttpServletRequest req) { + worldNewsInterest = Boolean.parseBoolean(req.getParameter(WORLD_PARAM)); + sportsInterest = Boolean.parseBoolean(req.getParameter(SPORTS_PARAM)); + businessInterest = Boolean.parseBoolean(req.getParameter(BUSINESS_PARAM)); + scienceNewsInterest = Boolean.parseBoolean(req.getParameter(SCIENCE_PARAM)); + String tempName = req.getParameter(NAME_PARAM); + if (tempName == null || tempName == "") { + tempName = DEFAULT_NAME; + } + name = tempName; + } + // getters and setters generated by Lombok +} +``` + +هذا السيرفلت لا يشكل جزءًا من النمط، ويقوم ببساطة بإعادة توجيه طلبات GET إلى JSP الصحيح. الطلبات PUT و POST و DELETE غير مدعومة وستعرض ببساطة رسالة خطأ. + +إدارة العرض في هذا المثال تتم من خلال فئة javabean: `ClientPropertiesBean`، التي تخزن تفضيلات المستخدم. + + +```html + + + + + + +<%ClientPropertiesBean propertiesBean = (ClientPropertiesBean) request.getAttribute("properties");%> +

Welcome <%= propertiesBean.getName()%>

+ + + + + + <% if(propertiesBean.isWorldNewsInterest()) { %> + + <% } else { %> + + <% } %> + + + + <% if(propertiesBean.isBusinessInterest()) { %> + + <% } else { %> + + <% } %> + + <% if(propertiesBean.isSportsInterest()) { %> + + <% } else { %> + + <% } %> + + + + <% if(propertiesBean.isScienceNewsInterest()) { %> + + <% } else { %> + + <% } %> + + +
<%@include file="worldNews.jsp"%><%@include file="localNews.jsp"%>
<%@include file="businessNews.jsp"%><%@include file="localNews.jsp"%><%@include file="sportsNews.jsp"%><%@include file="localNews.jsp"%>
<%@include file="scienceNews.jsp"%><%@include file="localNews.jsp"%>
+ + +``` + +هذه الصفحة JSP هي القالب. تقوم بإعلان جدول يحتوي على ثلاث صفوف، مع مكون في الصف الأول، واثنين من المكونات في الصف الثاني، ومكون واحد في الصف الثالث. + +تعتبر السكربتات في الملف جزءًا من استراتيجية إدارة العرض التي تتضمن مختلف العناصر الفرعية الذرية بناءً على تفضيلات المستخدم في الجافابين. + +فيما يلي مثالان على العناصر الفرعية الذرية المُحاكاة المستخدمة في التكوين: `businessNews.jsp`. + + +```html + + + + + + +

+ Generic Business News +

+ + + + + + + + + +
Stock prices up across the worldNew tech companies to invest in
Industry leaders unveil new projectPrice fluctuations and what they mean
+ + +``` + +`localNews.jsp` + +```html + + + +
+

+ Generic Local News +

+
    +
  • + Mayoral elections coming up in 2 weeks +
  • +
  • + New parking meter rates downtown coming tomorrow +
  • +
  • + Park renovations to finish by the next year +
  • +
  • + Annual marathon sign ups available online +
  • +
+
+ + +``` + +النتائج هي كما يلي: + +1) وضع المستخدم اسمه كـ `Tammy` في معلمات الطلب ولم يضع أي تفضيلات: ![alt text](./etc/images/noparam.png) +2) وضع المستخدم اسمه كـ `Johnny` في معلمات الطلب ولديه تفضيل للأخبار عن العالم، الأعمال والعلوم: ![alt text](./etc/images/threeparams.png) + +يتم تضمين العناصر الفرعية المختلفة مثل `worldNews.jsp`، `businessNews.jsp`، وغيرها بشكل مشروط بناءً على معلمات الطلب. + +**كيفية الاستخدام** + +لاختبار هذا المثال، تأكد من أن لديك Tomcat 10+ مثبتًا. قم بتكوين IDE الخاص بك لإنشاء ملف WAR من الوحدة ونشر هذا الملف على الخادم. + +IntelliJ: + +في `تشغيل` و `تحرير التكوينات` تأكد من أن خادم Tomcat هو أحد تكوينات التنفيذ. اذهب إلى تبويب النشر وتأكد من أنه يتم بناء artifact يسمى `composite-view:war exploded`. إذا لم يكن موجودًا، أضف واحدًا. + +تأكد من أن artifact يتم بناؤه من محتويات مجلد `web` ونتائج تجميع الوحدة. وجه مخرجات artifact إلى مكان مناسب. نفذ التكوين وشاهد الصفحة المستهدفة، واتبع التعليمات في تلك الصفحة للمتابعة. + +## مخطط الفئات + +![alt text](./etc/composite_view.png) + +يُظهر مخطط الفئات هنا الجافابين الذي يُعتبر مدير العرض. العروض هي ملفات JSP داخل مجلد الويب. + +## القابلية للتطبيق: + +استخدم نمط التصميم Composite View عندما: + +## تريد تمثيل الهياكل الجزئية للأشياء. + +* تتوقع أن الهياكل المركبة قد تتضمن مكونات جديدة في المستقبل. +* ترغب في أن يتمكن العملاء من تجاهل الفرق بين تكوينات الكائنات والكائنات الفردية. سيتعامل العملاء مع جميع الكائنات في الهيكل المركب بشكل موحد. + +## الاستخدامات المعروفة + +* واجهات المستخدم الرسومية (GUI) التي يمكن أن تحتوي فيها الأدوات على أدوات أخرى (على سبيل المثال، نافذة تحتوي على لوحات وأزرار وحقول نصية). +* هياكل الوثائق، مثل تمثيل الجداول التي تحتوي على صفوف، تحتوي هذه الصفوف بدورها على خلايا، والتي يمكن معالجتها جميعًا كعناصر في تسلسل هرمي موحد. + +## العواقب + +الفوائد: + +* مرونة كبيرة في إضافة مكونات جديدة: بما أن المكونات المركبة والعقد الورقية يتم التعامل معها بشكل موحد، يكون من الأسهل إضافة أنواع جديدة من المكونات. +* تبسيط الشيفرة البرمجية للعملاء: يمكن للعملاء التعامل مع الهياكل المركبة والعناصر الفردية بشكل موحد، مما يقلل من تعقيد الشيفرة البرمجية للعملاء. + +العيوب: + +* التعميم المفرط: قد يصبح تصميم النظام أكثر تعقيدًا إذا جعلت كل شيء مركبًا، خاصة إذا كانت تطبيقك لا يتطلب ذلك. +* صعوبة تطبيق القيود: قد يكون من الأصعب تقييد مكونات المركب لتكون من أنواع معينة فقط. + +## الأنماط ذات الصلة + +* [المزخرف](https://java-design-patterns.com/patterns/decorator/): بينما يستخدم مزخرف لإضافة مسؤوليات إلى الكائنات، يتم تصميم Composite لبناء هياكل كائنات. +* [الوزن الخفيف](https://java-design-patterns.com/patterns/flyweight/): يمكن دمج Composite غالبًا مع Flyweight لتنفيذ العقد الورقية المشتركة في هيكل مركب، مما يقلل من بصمة الذاكرة. +* [سلسلة المسؤولية](https://java-design-patterns.com/patterns/chain-of-responsibility/): يمكن استخدامها مع Composite للسماح للمكونات بتمرير الطلبات عبر التسلسل الهرمي. +* [المركب](https://java-design-patterns.com/patterns/composite/) +* [مساعد العرض](https://www.oracle.com/java/technologies/viewhelper.html) + +## الاعتمادات + +* [Core J2EE Patterns - Composite View](https://www.oracle.com/java/technologies/composite-view.html) +* [Composite View Design Pattern – Core J2EE Patterns](https://www.dineshonjava.com/composite-view-design-pattern/) +* [Patterns of Enterprise Application Architecture](https://amzn.to/49jpQG3) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/3xfntGJ) diff --git a/localization/ar/composite-view/etc/composite_view.png b/localization/ar/composite-view/etc/composite_view.png new file mode 100644 index 000000000000..66215d9416b8 Binary files /dev/null and b/localization/ar/composite-view/etc/composite_view.png differ diff --git a/localization/ar/composite-view/etc/images/noparam.png b/localization/ar/composite-view/etc/images/noparam.png new file mode 100644 index 000000000000..2979cf2bc657 Binary files /dev/null and b/localization/ar/composite-view/etc/images/noparam.png differ diff --git a/localization/ar/composite-view/etc/images/threeparams.png b/localization/ar/composite-view/etc/images/threeparams.png new file mode 100644 index 000000000000..9338dedb8885 Binary files /dev/null and b/localization/ar/composite-view/etc/images/threeparams.png differ diff --git a/localization/ar/composite/README.md b/localization/ar/composite/README.md new file mode 100644 index 000000000000..a90040cc02ab --- /dev/null +++ b/localization/ar/composite/README.md @@ -0,0 +1,222 @@ +--- +title: Composite +shortTitle: Composite +category: Structural +language: ar +tag: + - Gang of Four + - Object composition + - Recursion +--- + +## أيضًا يُعرف بـ + +* شجرة الكائنات +* الهيكل المركب + +## الهدف + +تركيب الكائنات في هياكل شجرية لتمثيل التسلسل الهرمي "جزء-كامل". يسمح نمط المركب للعملاء بمعاملة الكائنات الفردية وتركيبات الكائنات بطريقة موحدة. + +## الشرح + +مثال واقعي + +> تتكون كل جملة من كلمات، وكل كلمة تتكون بدورها من أحرف. كل واحد من هذه الكائنات قابل للطباعة ويمكن أن يكون له شيء مطبوع قبله أو بعده، مثلًا الجملة دائمًا تنتهي بنقطة، والكلمة دائمًا تملك مسافة قبلها. + +بكلمات بسيطة + +> يسمح نمط المركب للعملاء بمعاملة الكائنات الفردية بطريقة موحدة. + +تقول ويكيبيديا + +> في هندسة البرمجيات، نمط المركب هو نمط تصميم تقسيمي. يصف هذا النمط أنه يجب معاملة مجموعة من الكائنات بنفس الطريقة التي يتم بها معاملة كائن واحد. الهدف من المركب هو "تركيب" الكائنات في هياكل شجرية لتمثيل التسلسل الهرمي "جزء-كامل". يسمح تنفيذ نمط التركيب للعملاء بمعاملة الكائنات الفردية وتركيبات الكائنات بطريقة موحدة. + +**مثال برمجي** + +باستخدام مثالنا السابق، هنا لدينا الفئة الأساسية `LetterComposite` وأنواع مختلفة من الكائنات القابلة للطباعة مثل `Letter`, `Word`, و `Sentence`. + + +```java +public abstract class LetterComposite { + + private final List children = new ArrayList<>(); + + public void add(LetterComposite letter) { + children.add(letter); + } + + public int count() { + return children.size(); + } + + protected void printThisBefore() { + } + + protected void printThisAfter() { + } + + public void print() { + printThisBefore(); + children.forEach(LetterComposite::print); + printThisAfter(); + } +} + +public class Letter extends LetterComposite { + + private final char character; + + public Letter(char c) { + this.character = c; + } + + @Override + protected void printThisBefore() { + System.out.print(character); + } +} + +public class Word extends LetterComposite { + + public Word(List letters) { + letters.forEach(this::add); + } + + public Word(char... letters) { + for (char letter : letters) { + this.add(new Letter(letter)); + } + } + + @Override + protected void printThisBefore() { + System.out.print(" "); + } +} + +public class Sentence extends LetterComposite { + + public Sentence(List words) { + words.forEach(this::add); + } + + @Override + protected void printThisAfter() { + System.out.print("."); + } +} +``` + +## لدينا الآن مرسل لنقل الرسائل: + +```java +public class Messenger { + + LetterComposite messageFromOrcs() { + + var words = List.of( + new Word('W', 'h', 'e', 'r', 'e'), + new Word('t', 'h', 'e', 'r', 'e'), + new Word('i', 's'), + new Word('a'), + new Word('w', 'h', 'i', 'p'), + new Word('t', 'h', 'e', 'r', 'e'), + new Word('i', 's'), + new Word('a'), + new Word('w', 'a', 'y') + ); + + return new Sentence(words); + + } + + LetterComposite messageFromElves() { + + var words = List.of( + new Word('M', 'u', 'c', 'h'), + new Word('w', 'i', 'n', 'd'), + new Word('p', 'o', 'u', 'r', 's'), + new Word('f', 'r', 'o', 'm'), + new Word('y', 'o', 'u', 'r'), + new Word('m', 'o', 'u', 't', 'h') + ); + + return new Sentence(words); + + } + +} +``` + +## وبالتالي يمكن استخدامه كالتالي: + +```java +var messenger=new Messenger(); + + LOGGER.info("Message from the orcs: "); + messenger.messageFromOrcs().print(); + + LOGGER.info("Message from the elves: "); + messenger.messageFromElves().print(); +``` + +## مخرجات وحدة التحكم: + + + +``` +Message from the orcs: + Where there is a whip there is a way. +Message from the elves: + Much wind pours from your mouth. +``` + +## Diagrama de clases + +![alt text](./etc/composite.urm.png "Diagrama de clases compuestas") + +## Applicabilidad + +استخدم نمط **Composite** عندما: + +* ترغب في تمثيل الهياكل الجزئية للأشياء. +* ترغب في أن يتجاهل العملاء الفرق بين تراكيب الأشياء والأشياء الفردية. سيعالج العملاء جميع الكائنات في الهيكل المركب بشكل موحد. + +## الاستخدامات المعروفة + +* واجهات المستخدم الرسومية حيث يمكن للمكونات أن تحتوي على مكونات أخرى (مثل الألواح التي تحتوي على أزرار، تسميات، وألواح أخرى). +* تمثيلات أنظمة الملفات حيث يمكن للأدلة أن تحتوي على ملفات وأدلة أخرى. +* الهياكل التنظيمية حيث يمكن للقسم أن يحتوي على أقسام فرعية وموظفين. +* [java.awt.Container](http://docs.oracle.com/javase/8/docs/api/java/awt/Container.html) + و [java.awt.Component](http://docs.oracle.com/javase/8/docs/api/java/awt/Component.html) +* شجرة المكونات [Apache Wicket](https://github.com/apache/wicket)، + انظر [Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket-core/src/main/java/org/apache/wicket/Component.java) + و [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java) + +## العواقب + +### الفوائد: + +* يبسط الكود الخاص بالعميل، حيث يمكنه التعامل مع الهياكل المركبة والأشياء الفردية بشكل موحد. +* يسهل إضافة أنواع جديدة من المكونات، حيث لا يتعين تعديل الكود الموجود. + +### العيوب: + +* قد يجعل التصميم عامًا جدًا. قد يكون من الصعب تقييد مكونات المركب. +* قد يصعب تحديد أنواع المكونات في المركب. + +## الأنماط المتعلقة + +* [Flyweight](https://java-design-patterns.com/patterns/flyweight/): يمكن لـ Composite استخدام Flyweight لمشاركة + مثيلات المكونات بين عدة مركبات. +* [Iterador](https://java-design-patterns.com/patterns/iterator/): يمكن استخدامه لتصفح الهياكل المركبة. +* [Visitante](https://java-design-patterns.com/patterns/visitor/): يمكن تطبيق عملية على الهيكل المركب. + +## الائتمانات + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) +* [Pattern-Oriented Software Architecture, Volume 1: A System of Patterns](https://amzn.to/3xoLAmi) +* [Patterns of Enterprise Application Architecture](https://amzn.to/3vBKXWb) diff --git a/localization/ar/composite/etc/composite.urm.png b/localization/ar/composite/etc/composite.urm.png new file mode 100644 index 000000000000..93c160f6450a Binary files /dev/null and b/localization/ar/composite/etc/composite.urm.png differ diff --git a/localization/ar/context-object/README.md b/localization/ar/context-object/README.md new file mode 100644 index 000000000000..77fd8d8b754c --- /dev/null +++ b/localization/ar/context-object/README.md @@ -0,0 +1,188 @@ +--- +title: Context object +shortTitle: Context object +category: Creational +language: ar +tags: + - Data access +--- + +## الاسم / التصنيف + +كائن السياق + +## يعرف أيضًا باسم + +السياق، تجميع السياق + +## الغرض + +فصل البيانات عن الفئات الخاصة بالبروتوكول وتخزين بيانات السياق في كائن مستقل عن التكنولوجيا الخاصة بالبروتوكول الأساسي. + +## الشرح + +مثال من العالم الواقعي + +> يحتوي هذا التطبيق على طبقات مختلفة موسومة مثل A وB وC، كل واحدة منها تستخرج معلومات محددة من سياق مشابه لاستخدامها لاحقًا في البرنامج. تمرير كل قطعة من المعلومات بشكل فردي سيكون غير فعال، لذا هناك حاجة إلى طريقة لتخزين وتمرير المعلومات بشكل فعال. +> بكلمات بسيطة + +> أنشئ كائنًا وخزن البيانات هناك، ثم مرر هذا الكائن حيثما كان مطلوبًا. + +[Core J2EE Patterns](http://corej2eepatterns.com/ContextObject.htm) يقول + +> استخدم كائن السياق (Context Object) لتغليف الحالة بطريقة مستقلة عن البروتوكول ليتم مشاركتها عبر تطبيقك. + +**مثال برمجي** + +نحدد البيانات التي يحتوي عليها كائن السياق (Context Object) للخدمة `ServiceContext`. + + +```Java +public class ServiceContext { + + String ACCOUNT_SERVICE, SESSION_SERVICE, SEARCH_SERVICE; + + public void setACCOUNT_SERVICE(String ACCOUNT_SERVICE) { + this.ACCOUNT_SERVICE = ACCOUNT_SERVICE; + } + + public void setSESSION_SERVICE(String SESSION_SERVICE) { + this.SESSION_SERVICE = SESSION_SERVICE; + } + + public void setSEARCH_SERVICE(String SEARCH_SERVICE) { + this.SEARCH_SERVICE = SEARCH_SERVICE; + } + + public String getACCOUNT_SERVICE() { + return ACCOUNT_SERVICE; + } + + public String getSESSION_SERVICE() { + return SESSION_SERVICE; + } + + public String getSEARCH_SERVICE() { + return SEARCH_SERVICE; + } + + public String toString() { return ACCOUNT_SERVICE + " " + SESSION_SERVICE + " " + SEARCH_SERVICE;} +} +``` + +يتم إنشاء واجهة `ServiceContextFactory` تُستخدم في أجزاء من التطبيق لإنشاء كائنات السياق. + + +```Java +public class ServiceContextFactory { + + public static ServiceContext createContext() { + return new ServiceContext(); + } +} +``` + +إنشاء كائن السياق في الطبقة الأولى `LayerA` والطبقة المجاورة `LayerB` حتى يتم استدعاء السياق في الطبقة الحالية `LayerC`، التي تقوم بترتيب الكائن. + + +```Java +public class LayerA { + + private static ServiceContext context; + + public LayerA() { + context = ServiceContextFactory.createContext(); + } + + public static ServiceContext getContext() { + return context; + } + + public void addAccountInfo(String accountService) { + context.setACCOUNT_SERVICE(accountService); + } +} + +public class LayerB { + + private static ServiceContext context; + + public LayerB(LayerA layerA) { + this.context = layerA.getContext(); + } + + public static ServiceContext getContext() { + return context; + } + + public void addSessionInfo(String sessionService) { + context.setSESSION_SERVICE(sessionService); + } +} + +public class LayerC { + + public static ServiceContext context; + + public LayerC(LayerB layerB) { + this.context = layerB.getContext(); + } + + public static ServiceContext getContext() { + return context; + } + + public void addSearchInfo(String searchService) { + context.setSEARCH_SERVICE(searchService); + } +} +``` + +إليك كائن السياق والطبقات قيد التنفيذ. + + +```Java +var layerA = new LayerA(); +layerA.addAccountInfo(SERVICE); +LOGGER.info("Context = {}",layerA.getContext()); +var layerB = new LayerB(layerA); +layerB.addSessionInfo(SERVICE); +LOGGER.info("Context = {}",layerB.getContext()); +var layerC = new LayerC(layerB); +layerC.addSearchInfo(SERVICE); +LOGGER.info("Context = {}",layerC.getContext()); +``` + +إخراج البرنامج: + + +```Java +Context = SERVICE null null +Context = SERVICE SERVICE null +Context = SERVICE SERVICE SERVICE +``` + +## رسم توضيحي للفئات + +![alt text](./etc/context-object.png "كائن السياق") + +## القابلية للتطبيق + +استخدم نمط كائن السياق (Context Object) لـ: + +* مشاركة المعلومات بين الطبقات المختلفة للنظام. +* فصل البيانات عن السياقات المحددة للبروتوكولات. +* عرض واجهات البرمجة ذات الصلة فقط ضمن السياق. + +## الاستخدامات المعروفة + +* [Spring: ApplicationContext](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html) +* [Oracle: SecurityContext](https://docs.oracle.com/javaee/7/api/javax/ws/rs/core/SecurityContext.html) +* [Oracle: ServletContext](https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html) + +## الفضل + +* [Core J2EE Design Patterns](https://amzn.to/3IhcY9w) +* [موقع Core J2EE Design Patterns - كائن السياق](http://corej2eepatterns.com/ContextObject.htm) +* [Allan Kelly - نمط تجميع السياق](https://accu.org/journals/overload/12/63/kelly_246/) +* [Arvid S. Krishna وآخرون - كائن السياق](https://www.dre.vanderbilt.edu/~schmidt/PDF/Context-Object-Pattern.pdf) diff --git a/localization/ar/context-object/etc/context-object.png b/localization/ar/context-object/etc/context-object.png new file mode 100644 index 000000000000..a1f670812f7b Binary files /dev/null and b/localization/ar/context-object/etc/context-object.png differ diff --git a/localization/ar/converter/README.md b/localization/ar/converter/README.md new file mode 100644 index 000000000000..cef553e1da32 --- /dev/null +++ b/localization/ar/converter/README.md @@ -0,0 +1,102 @@ +--- +title: Converter +shortTitle: Converter +category: Creational +language: ar +tag: + - Decoupling +--- + +## الهدف + +الهدف من نمط المحول (Converter) هو توفير وسيلة عامة وشائعة للتحويل الثنائي الاتجاه بين الأنواع المقابلة، مما يتيح تنفيذًا نظيفًا حيث لا يحتاج الأنواع إلى معرفة بعضها البعض. علاوة على ذلك، يقدم نمط المحول تعيينًا ثنائي الاتجاه للمجموعات الثنائية الاتجاه، مما يقلل من الكود المكرر إلى الحد الأدنى. + +## الشرح + +مثال من الحياة الواقعية + +> في التطبيقات الواقعية، غالبًا ما يحدث أن يتكون طبقة قاعدة البيانات من كيانات تحتاج إلى أن يتم تحويلها إلى DTO لاستخدامها في طبقة منطق الأعمال. يتم إجراء تحويل مشابه لعدد potentially ضخم من الفئات ونحتاج إلى طريقة عامة لتحقيق ذلك. + +ببساطة + +> يسهل نمط التحويل (Converter) تعيين الكائنات من فئة إلى كائنات من فئة أخرى. + +**مثال برمجي** + +نحتاج إلى حل عام لمشكلة التعيين. لذلك، دعونا نقدم محولًا عامًا. + + +```java +public class Converter { + + private final Function fromDto; + private final Function fromEntity; + + public Converter(final Function fromDto, final Function fromEntity) { + this.fromDto = fromDto; + this.fromEntity = fromEntity; + } + + public final U convertFromDto(final T dto) { + return fromDto.apply(dto); + } + + public final T convertFromEntity(final U entity) { + return fromEntity.apply(entity); + } + + public final List createFromDtos(final Collection dtos) { + return dtos.stream().map(this::convertFromDto).collect(Collectors.toList()); + } + + public final List createFromEntities(final Collection entities) { + return entities.stream().map(this::convertFromEntity).collect(Collectors.toList()); + } +} +``` + +## المحولات المتخصصة ترث من هذه الفئة الأساسية كما يلي. + + +```java +public class UserConverter extends Converter { + + public UserConverter() { + super(UserConverter::convertToEntity, UserConverter::convertToDto); + } + + private static UserDto convertToDto(User user) { + return new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), user.getUserId()); + } + + private static User convertToEntity(UserDto dto) { + return new User(dto.getFirstName(), dto.getLastName(), dto.isActive(), dto.getEmail()); + } + +} +``` + +الآن يصبح التحويل بين `User` و `UserDto` أمرًا تافهًا. + + +```java +var userConverter = new UserConverter(); +var dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com"); +var user = userConverter.convertFromDto(dtoUser); +``` + +## مخطط الفئات + +![alt text](./etc/converter.png "نمط المحول") + +## القابلية للتطبيق + +استخدم نمط المحول في الحالات التالية: + +* عندما يكون لديك أنواع تتطابق منطقيًا مع بعضها البعض وتحتاج إلى تحويل الكيانات بينهما. +* عندما ترغب في توفير أشكال مختلفة لتحويل الأنواع اعتمادًا على السياق. +* كلما قدمت كائن نقل البيانات (DTO)، من المحتمل أن تحتاج إلى تحويله إلى معادله في المجال. + +## الاعتمادات + +* [نمط المحول في Java 8](http://www.xsolve.pl/blog/converter-pattern-in-java-8/) diff --git a/localization/ar/converter/etc/converter.png b/localization/ar/converter/etc/converter.png new file mode 100644 index 000000000000..01435ef5ae29 Binary files /dev/null and b/localization/ar/converter/etc/converter.png differ diff --git a/localization/ar/crtp/README.md b/localization/ar/crtp/README.md new file mode 100644 index 000000000000..f7ab6de3a210 --- /dev/null +++ b/localization/ar/crtp/README.md @@ -0,0 +1,139 @@ +--- +title: Curiously Recurring Template Pattern +language: ar +category: Structural +tag: +- Extensibility +- Instantiation +--- + +## الاسم / التصنيف + +نمط القالب المتكرر بغرابة + +## المعروف أيضًا باسم + +الحدود النوعية المتكررة، الجينيريك المتكرر + +## الهدف + +السماح للمكونات المشتقة بالوراثة من بعض الوظائف من مكون أساسي تكون متوافقة مع النوع المشتق. + +## الشرح + +مثال حقيقي + +> لتنظيم حدث للفنون القتالية المختلطة، من المهم التأكد من أن المباريات تتم بين رياضيين في نفس فئة الوزن. هذا يضمن تجنب المواجهات بين مقاتلين من أحجام مختلفة للغاية، مثل الوزن الثقيل ضد الوزن الخفيف. + +ببساطة + +> جعل بعض الطرق داخل نوع ما تقبل المعاملات الخاصة بأنواعه الفرعية. + +تقول ويكيبيديا + +> نمط القالب المتكرر بغرابة (CRTP) هو أسلوب برمجي، بدأ في C++، حيث تقوم فئة X بالاشتقاق من تطبيق قالب فئة باستخدام X نفسها كحجة للقالب. + +**مثال برمجي** + +لنحدد الواجهة العامة Fighter + + +```java +public interface Fighter { + + void fight(T t); + +} +``` + +تستخدم فئة `MMAFighter` لإنشاء مقاتلين يتميزون بفئة وزنهم. + + +```java +public class MmaFighter> implements Fighter { + + private final String name; + private final String surname; + private final String nickName; + private final String speciality; + + public MmaFighter(String name, String surname, String nickName, String speciality) { + this.name = name; + this.surname = surname; + this.nickName = nickName; + this.speciality = speciality; + } + + @Override + public void fight(T opponent) { + LOGGER.info("{} is going to fight against {}", this, opponent); + } + + @Override + public String toString() { + return name + " \"" + nickName + "\" " + surname; + } +} +``` + +فيما يلي بعض الأنواع الفرعية لـ `MMAFighter`: + + +```java +class MmaBantamweightFighter extends MmaFighter { + + public MmaBantamweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} + +public class MmaHeavyweightFighter extends MmaFighter { + + public MmaHeavyweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} +``` + +يمكن للمقاتل أن يواجه خصمًا من نفس فئة الوزن، وإذا كان الخصم من فئة وزن مختلفة يحدث خطأ. + + +```java +MmaBantamweightFighter fighter1 = new MmaBantamweightFighter("Joe", "Johnson", "The Geek", "Muay Thai"); +MmaBantamweightFighter fighter2 = new MmaBantamweightFighter("Ed", "Edwards", "The Problem Solver", "Judo"); +fighter1.fight(fighter2); // This is fine + +MmaHeavyweightFighter fighter3 = new MmaHeavyweightFighter("Dave", "Davidson", "The Bug Smasher", "Kickboxing"); +MmaHeavyweightFighter fighter4 = new MmaHeavyweightFighter("Jack", "Jackson", "The Pragmatic", "Brazilian Jiu-Jitsu"); +fighter3.fight(fighter4); // This is fine too + +fighter1.fight(fighter3); // This will raise a compilation error +``` + +## Diagrama de clases + +![alt text](./etc/crtp.png "Diagrama de clases CRTP") + +## قابلية التطبيق + +استخدم نمط "القالب المتكرر بشكل غريب" عندما: + +* تواجه تعارضات في الأنواع عند ربط الأساليب في هيكل الكائنات +* ترغب في استخدام طريقة من الفئة معلمة يمكن أن تقبل الفئات الفرعية كوسائط، مما يسمح بتطبيقها على الكائنات التي ترث من هذه الفئة +* ترغب في أن تعمل بعض الأساليب فقط مع كائنات من نفس النوع، على سبيل المثال، لتحقيق المقارنة المتبادلة. + +## دروس تعليمية + +* [مدونة NuaH](https://nuah.livejournal.com/328187.html) +* إجابة من Yogesh Umesh Vaity على [ماذا يعني "الحدود التكرارية للنوع" في الأنواع العامة؟](https://stackoverflow.com/questions/7385949/what-does-recursive-type-bound-in-generics-mean) + +## الاستخدامات المعروفة + +* [java.lang.Enum](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Enum.html) + +## الاعتمادات + +* [كيف أفك تشفير "Enum>"؟](http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106) +* الفصل 5 Generics، العنصر 30 في [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb) diff --git a/localization/ar/crtp/etc/crtp.png b/localization/ar/crtp/etc/crtp.png new file mode 100644 index 000000000000..a348c8af6175 Binary files /dev/null and b/localization/ar/crtp/etc/crtp.png differ diff --git a/localization/ar/data-locality/README.md b/localization/ar/data-locality/README.md new file mode 100644 index 000000000000..9150d2b51bc6 --- /dev/null +++ b/localization/ar/data-locality/README.md @@ -0,0 +1,30 @@ +--- +title: Data Locality +shortTitle: Data Locality +category: Behavioral +language: ar +tag: + - Game programming + - Performance +--- + +## الهدف +يُسرع الوصول إلى الذاكرة من خلال تنظيم البيانات للاستفادة من ذاكرة التخزين المؤقت في وحدة المعالجة المركزية. + +تحتوي وحدات المعالجة المركزية الحديثة على ذاكرات تخزين مؤقت لتسريع الوصول إلى الذاكرة. يمكنها الوصول بسرعة أكبر إلى الذاكرة المجاورة لذاكرة تم الوصول إليها مؤخرًا. استفد من ذلك لتحسين الأداء عن طريق زيادة محلية البيانات، من خلال الحفاظ عليها في ذاكرة متجاورة بالترتيب الذي تعالجها فيه. + +## مخطط الفئات +![alt text](./etc/data-locality.urm.png "Data Locality pattern class diagram") + +## قابلية التطبيق + +* كما هو الحال مع معظم التحسينات، القاعدة الأولى لاستخدام نمط "محلية البيانات" هي عندما يكون لديك مشكلة في الأداء. +* مع هذا النمط بشكل خاص، ستحتاج أيضًا إلى التأكد من أن مشاكل الأداء ناتجة عن فقدان الذاكرة المؤقتة. + +## مثال من العالم الحقيقي + +* محرك الألعاب [Artemis](http://gamadu.com/artemis/) هو واحد من أولى وأكثر الأطر شهرة التي تستخدم معرفات بسيطة لكائنات اللعبة. + +## الاعتمادات + +* [أنماط برمجة الألعاب - أنماط التحسين: محلية البيانات](http://gameprogrammingpatterns.com/data-locality.html) diff --git a/localization/ar/data-locality/etc/data-locality.urm.png b/localization/ar/data-locality/etc/data-locality.urm.png new file mode 100644 index 000000000000..d19873739551 Binary files /dev/null and b/localization/ar/data-locality/etc/data-locality.urm.png differ diff --git a/localization/ar/decorator/README.md b/localization/ar/decorator/README.md new file mode 100644 index 000000000000..e36cc2695d79 --- /dev/null +++ b/localization/ar/decorator/README.md @@ -0,0 +1,164 @@ +--- +title: Decorator +shortTitle: Decorator +category: Structural +language: ar +tag: + - Gang of Four + - Extensibility +--- + +## المعروف أيضا باسم + +التغليف + +## الهدف + +إضافة مسؤوليات إضافية إلى كائن بطريقة ديناميكية. يوفر الزخرفة بديلاً مرنًا للوراثة لتوسيع الوظائف. + +## الشرح + +مثال من العالم الحقيقي + +> في التلال القريبة يعيش تيرول غاضب. عادة ما يكون يده عارية، ولكن في بعض الأحيان يحمل سلاحًا. لتسليح التيرول لا يتطلب الأمر إنشاء تيرول جديد بل تزيينه ديناميكيًا بسلاح مناسب. + +ببساطة + +> يتيح لك نمط الزخرفة تغيير سلوك كائن ديناميكيًا أثناء وقت التشغيل من خلال تغليفه في كائن من فئة الزخرفة. + +يقول Wikipedia + +> في البرمجة الكائنية التوجه، يعتبر نمط الزخرفة نمط تصميم يسمح بإضافة سلوك إلى كائن فردي، سواء بطريقة ثابتة أو ديناميكية، دون التأثير على سلوك الكائنات الأخرى من نفس الفئة. يُعتبر نمط الزخرفة مفيدًا للامتثال لمبدأ المسؤولية الفردية، حيث يسمح بتقسيم الوظائف بين الفئات ذات مجالات الاهتمام الفريدة، وكذلك لمبدأ الانفتاح-الإغلاق، من خلال السماح بتمديد وظائف الفئة دون تعديلها. + +**مثال برمجي** + +لنأخذ مثال التيرول. في البداية لدينا `SimpleTroll` الذي ينفذ الواجهة `Troll`: + + +```java +public interface Troll { + void atacar(); + int getPoderAtaque(); + void huirBatalla(); +} + +@Slf4j +public class SimpleTroll implements Troll { + + @Override + public void atacar() { + LOGGER.info("¡El troll intenta atraparte!"); + } + + @Override + public int getPoderAtaque() { + return 10; + } + + @Override + public void huirBatalla() { + LOGGER.info("¡El troll chilla de horror y huye!"); + } +} +``` + +بعد ذلك، نريد إضافة عصا للتيرول. يمكننا فعل ذلك بشكل ديناميكي باستخدام الزخرفة: + + +```java +@Slf4j +public class TrollConGarrote implements Troll { + + private final Troll decorado; + + public TrollConGarrote(Troll decorado) { + this.decorado = decorado; + } + + @Override + public void atacar() { + decorado.atacar(); + LOGGER.info("¡El troll te golpea con un garrote!"); + } + + @Override + public int getPoderAtaque() { + return decorado.getPoderAtaque() + 10; + } + + @Override + public void huirBatalla() { + decorado.huirBatalla(); + } +} +``` + +إليك التيرول في العمل: + + +```java +// التيرول البسيط +LOGGER.info("تيرول ذو مظهر بسيط يقترب."); +var troll = new SimpleTroll(); +troll.atacar(); +troll.huirBatalla(); +LOGGER.info("قوة التيرول البسيط: {}.\n", troll.getPoderAtaque()); + +// تغيير سلوك التيرول البسيط عن طريق إضافة ديكور +LOGGER.info("تيرول يحمل عصا ضخمة يفاجئك."); +var trollConGarrote = new TrollConGarrote(troll); +trollConGarrote.atacar(); +trollConGarrote.huirBatalla(); +LOGGER.info("قوة التيرول مع العصا: {}.\n", trollConGarrote.getPoderAtaque()); + +``` + +نتيجة البرنامج: + +```java +تيرول ذو مظهر بسيط يقترب. +!التيرول يحاول الإمساك بك! +!التيرول يصرخ من الرعب ويهرب! +قوة التيرول البسيط: 10. + +تيرول يحمل عصا ضخمة يفاجئك. +!التيرول يحاول الإمساك بك! +!التيرول يضربك بعصا ضخمة! +!التيرول يصرخ من الرعب ويهرب! +قوة التيرول مع العصا: 20. + +``` + +## مخطط الفئات + +![alt text](./etc/decorator.urm.png "مخطط فئات نمط الديكور") + +## القابلية للتطبيق + +يُستخدم نمط الديكور لـ: + +* إضافة مسؤوليات إلى كائنات فردية بشكل ديناميكي وشفاف، أي دون التأثير على الكائنات الأخرى. +* للمسؤوليات التي يمكن إزالتها. +* عندما يكون التوسيع بواسطة الفئات الفرعية غير عملي. في بعض الأحيان، قد يكون من الممكن إضافة عدد كبير من الامتدادات المستقلة التي قد تؤدي إلى انفجار في الفئات الفرعية لدعم كل مجموعة من التركيبات. أو قد تكون تعريفات الفئات مخفية أو غير متاحة للفئات الفرعية. + +## الدروس التعليمية + +* [دورة نمط الديكور](https://www.journaldev.com/1540/decorator-design-pattern-in-java-example) + +## الاستخدامات المعروفة + +* [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html)، [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html)، + [java.io.Reader](http://docs.oracle.com/javase/8/docs/api/java/io/Reader.html) + و [java.io.Writer](http://docs.oracle.com/javase/8/docs/api/java/io/Writer.html) +* [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-) +* [java.util.Collections#unmodifiableXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableCollection-java.util.Collection-) +* [java.util.Collections#checkedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#checkedCollection-java.util.Collection-java.lang.Class-) + +## الاعتمادات + +* [تصميم الأنماط: عناصر البرمجيات القابلة لإعادة الاستخدام](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [البرمجة الوظيفية في جافا: تسخير قوة تعبيرات لامبدا في جافا 8](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b) +* [أنماط تصميم J2EE](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [رأس الأنماط: دليل سهل الفهم](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [إعادة الهيكلة إلى الأنماط](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) +* [أنماط تصميم J2EE](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) diff --git a/localization/ar/decorator/etc/decorator.urm.png b/localization/ar/decorator/etc/decorator.urm.png new file mode 100644 index 000000000000..141c0563f0c6 Binary files /dev/null and b/localization/ar/decorator/etc/decorator.urm.png differ diff --git a/localization/ar/delegation/README.md b/localization/ar/delegation/README.md new file mode 100644 index 000000000000..1f0d84734dd1 --- /dev/null +++ b/localization/ar/delegation/README.md @@ -0,0 +1,119 @@ +--- +title: Delegation +shortTitle: Delegation +category: Structural +language: ar +tag: + - Decoupling +--- + +## يُعرف أيضًا بـ + +نمط الوكيل (Proxy Pattern) + +## الهدف + +هي تقنية يتم من خلالها أن يعبر كائن عن سلوك معين للخارج ولكنه في الواقع يفوض مسؤولية تنفيذ ذلك السلوك إلى كائن مرتبط. + +## الشرح + +مثال من الواقع + +> لنتخيل أن لدينا مغامرين يقاتلون ضد وحوش بأسلحة مختلفة حسب مهاراتهم وقدراتهم. يجب أن نكون قادرين على تجهيزهم بأسلحة مختلفة دون الحاجة لتعديل الشيفرة المصدرية لكل سلاح. يقوم نمط التفويض بهذا من خلال تفويض العمل بشكل ديناميكي إلى كائن معين يقوم بتنفيذ واجهة بها الطرق ذات الصلة. + +يقول ويكيبيديا + +> في البرمجة الشيئية، يشير التفويض إلى تقييم أحد الأعضاء (خاصية أو طريقة) لكائن (المستقبل) في سياق كائن آخر أصلي (المرسل). يمكن أن يتم التفويض بشكل صريح، عن طريق تمرير الكائن المرسل إلى الكائن المستقبل، وهو ما يمكن القيام به في أي لغة برمجة موجهة للكائنات؛ أو ضمنيًا، من خلال قواعد البحث عن الأعضاء في اللغة، وهو ما يتطلب دعم اللغة لهذه الوظيفة. + +**مثال برمجي** + +لدينا واجهة `Printer` وثلاثة تطبيقات هي `CanonPrinter`، `EpsonPrinter` و `HpPrinter`. + +```java +public interface Printer { + void print(final String message); +} + +@Slf4j +public class CanonPrinter implements Printer { + @Override + public void print(String message) { + LOGGER.info("Canon Printer : {}", message); + } +} + +@Slf4j +public class EpsonPrinter implements Printer { + @Override + public void print(String message) { + LOGGER.info("Epson Printer : {}", message); + } +} + +@Slf4j +public class HpPrinter implements Printer { + @Override + public void print(String message) { + LOGGER.info("HP Printer : {}", message); + } +} +``` + +El `PrinterController` puede ser utilizado como un `Printer` delegando cualquier trabajo manejado por este +a un objeto que la implemente. + +```java +public class PrinterController implements Printer { + + private final Printer printer; + + public PrinterController(Printer printer) { + this.printer = printer; + } + + @Override + public void print(String message) { + printer.print(message); + } +} +``` + +الآن في شفرة العميل، يمكن لوحدات تحكم الطابعة طباعة الرسائل بطرق مختلفة اعتمادًا على الكائن الذي يتم تفويض العمل إليه. + + +```java +private static final String MESSAGE_TO_PRINT = "hello world"; + +var hpPrinterController = new PrinterController(new HpPrinter()); +var canonPrinterController = new PrinterController(new CanonPrinter()); +var epsonPrinterController = new PrinterController(new EpsonPrinter()); + +hpPrinterController.print(MESSAGE_TO_PRINT); +canonPrinterController.print(MESSAGE_TO_PRINT); +epsonPrinterController.print(MESSAGE_TO_PRINT) +``` + +مخرجات البرنامج: + + +```java +HP Printer : hello world +Canon Printer : hello world +Epson Printer : hello world +``` + +## مخطط الفئات + +![alt text](./etc/delegation.png "Delegate") + +## القابلية للتطبيق + +استخدم نمط التفويض لتحقيق ما يلي: + +* تقليل ارتباط الأساليب بالفئة الخاصة بها +* مكونات تتصرف بشكل متطابق، مع مراعاة أن هذا الوضع قد يتغير في المستقبل. + +## الاعتمادات + +* [نمط التفويض: ويكيبيديا](https://en.wikipedia.org/wiki/Delegation_pattern) +* [نمط الوكيل: ويكيبيديا](https://en.wikipedia.org/wiki/Proxy_pattern) diff --git a/localization/ar/delegation/etc/delegation.png b/localization/ar/delegation/etc/delegation.png new file mode 100644 index 000000000000..375ef4d6b00f Binary files /dev/null and b/localization/ar/delegation/etc/delegation.png differ diff --git a/localization/ar/dependency-injection/README.md b/localization/ar/dependency-injection/README.md new file mode 100644 index 000000000000..9b45931c6f03 --- /dev/null +++ b/localization/ar/dependency-injection/README.md @@ -0,0 +1,101 @@ +--- +title: Dependency Injection +shortTitle: Dependency Injection +category: Creational +language: ar +tag: + - Decoupling +--- + +## الغرض + +حقن التبعيات هو نمط تصميم برمجي يتم فيه حقن واحدة أو أكثر من التبعيات (أو الخدمات) إلى كائن تابع (أو عميل) وتصبح جزءاً من حالة العميل. يفصل النمط بين إنشاء التبعيات للعميل وسلوكه الخاص، مما يسمح بتصاميم برامج منخفضة الارتباط وتلتزم بمبادئ عكس التحكم والمسؤولية الواحدة. + +## الشرح + +مثال من العالم الحقيقي + +> يحب الساحر العجوز ملء غليونه والتدخين من وقت لآخر. ومع ذلك، لا يريد أن يعتمد على علامة تجارية واحدة من التبغ، بل يحب أن يتمكن من الاستمتاع بها جميعاً بشكل قابل للتبادل. + +بكلمات بسيطة + +> حقن التبعيات يفصل إنشاء التبعيات للعميل عن سلوكه الخاص. + +تقول ويكيبيديا + +> في هندسة البرمجيات، حقن التبعيات هو تقنية يحصل فيها كائن على كائنات أخرى يعتمد عليها. تُسمى هذه الكائنات الأخرى بالتبعيات. + +**مثال برمجي** + +لنقم أولاً بتقديم واجهة التبغ `Tobacco` والعلامات التجارية المحددة. + + +```java +@Slf4j +public abstract class Tobacco { + + public void smoke(Wizard wizard) { + LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(), + this.getClass().getSimpleName()); + } +} + +public class SecondBreakfastTobacco extends Tobacco { +} + +public class RivendellTobacco extends Tobacco { +} + +public class OldTobyTobacco extends Tobacco { +} +``` + +التالي هو واجهة `Wizard` وتنفيذها. + + +```java +public interface Wizard { + + void smoke(); +} + +public class AdvancedWizard implements Wizard { + + private final Tobacco tobacco; + + public AdvancedWizard(Tobacco tobacco) { + this.tobacco = tobacco; + } + + @Override + public void smoke() { + tobacco.smoke(this); + } +} +``` + +وأخيراً يمكننا أن نثبت مدى سهولة إعطاء التبغ `Tobacco` لأي علامة تجارية قديمة للساحر. + + +```java + var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco()); + advancedWizard.smoke(); +``` + +## Class Diagram + +![alt text](./etc/dependency-injection.png "Dependency Injection") + +## Applicability + +Use the Dependency Injection pattern when: + +* You need to eliminate the knowledge of the concrete implementation of the object. +* To allow unit testing of classes in isolation using mock objects or stubs. + +## Credits + +* [Dependency Injection Principles, Practices, and Patterns](https://www.amazon.com/gp/product/161729473X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=161729473X&linkId=57079257a5c7d33755493802f3b884bd) +* [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=javadesignpat-20&linkId=2c390d89cc9e61c01b9e7005c7842871) +* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://www.amazon.com/gp/product/1788296257/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1788296257&linkId=4e9137a3bf722a8b5b156cce1eec0fc1) +* [Google Guice: Agile Lightweight Dependency Injection Framework](https://www.amazon.com/gp/product/1590599977/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1590599977&linkId=3b10c90b7ba480a1b7777ff38000f956) diff --git a/localization/ar/dependency-injection/etc/dependency-injection.png b/localization/ar/dependency-injection/etc/dependency-injection.png new file mode 100644 index 000000000000..2a92c9eb228b Binary files /dev/null and b/localization/ar/dependency-injection/etc/dependency-injection.png differ diff --git a/localization/ar/dirty-flag/README.md b/localization/ar/dirty-flag/README.md new file mode 100644 index 000000000000..4c9b5742e942 --- /dev/null +++ b/localization/ar/dirty-flag/README.md @@ -0,0 +1,28 @@ +--- +title: Dirty Flag +shortTitle: Dirty Flag +category: Behavioral +language: ar +tag: + - Game programming + - Performance +--- + +## Also known as +* IsDirty pattern + +## Purpose +Avoid the costly re-acquisition of resources. Resources retain their identity, are stored in some fast-access storage, and are reused to avoid having to acquire them again. + +## Class Diagram +![alt text](./etc/dirty-flag.png "Dirty Flag") + +## Applicability +Use the Dirty Flag pattern when + +* The repetitive acquisition, initialization, and release of the same resource causes unnecessary performance overhead. + +## Credits + +* [Design Patterns: Dirty Flag](https://www.takeupcode.com/podcast/89-design-patterns-dirty-flag/) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) diff --git a/localization/ar/dirty-flag/etc/dirty-flag.png b/localization/ar/dirty-flag/etc/dirty-flag.png new file mode 100644 index 000000000000..98d4f679d17c Binary files /dev/null and b/localization/ar/dirty-flag/etc/dirty-flag.png differ diff --git a/localization/ar/double-buffer/README.md b/localization/ar/double-buffer/README.md new file mode 100644 index 000000000000..46b47a33ef48 --- /dev/null +++ b/localization/ar/double-buffer/README.md @@ -0,0 +1,245 @@ +--- +title: Double Buffer +shortTitle: Double Buffer +category: Behavioral +language: ar +tag: + - Performance + - Game programming +--- + +## الهدف + +الذاكرة المزدوجة هي مصطلح يُستخدم لوصف جهاز يحتوي على مخزنين. استخدام المخازن المتعددة يزيد من الأداء العام للجهاز ويساعد في تجنب الاختناقات. يُظهر هذا المثال استخدام الذاكرة المزدوجة في الرسومات. يُستخدم لعرض صورة أو إطار بينما يتم تخزين إطار آخر في المخزن ليتم عرضه لاحقًا. هذه الطريقة تجعل الرسوم المتحركة والألعاب تبدو أكثر واقعية مقارنة بتلك التي تُعرض باستخدام الذاكرة الفردية. + +## الشرح + +مثال من الحياة الواقعية +> مثال نموذجي، ويجب أن تتعامل معه جميع محركات الألعاب، هو التقديم. عندما يرسم اللعبة العالم الذي يراه المستخدمون، تقوم بذلك قطعة قطعة: الجبال البعيدة، التلال المتدحرجة، الأشجار، كل منها على حدة. إذا رأى المستخدم كيف يتم رسم العرض بشكل تدريجي، فسوف تنكسر الوهم لعالم متماسك. يجب تحديث المشهد بسلاسة وسرعة، مع عرض سلسلة من الإطارات المكتملة، يظهر كل منها فورًا. يحل التقديم المزدوج هذه المشكلة. + +ببساطة +> يضمن حالة يتم عرضها بشكل صحيح بينما يتم تعديل تلك الحالة تدريجيًا. يتم استخدامه كثيرًا في الرسومات الحاسوبية. + +ويكيبيديا تقول +> في علوم الكمبيوتر، التخزين في الذاكرة المتعددة هو استخدام أكثر من مخزن واحد لحمل كتلة من البيانات، بحيث يرى "القارئ" نسخة كاملة (على الرغم من أنها قديمة) من البيانات، بدلاً من نسخة محدثة جزئيًا من البيانات التي يقوم "الكاتب" بإنشائها. يُستخدم ذلك كثيرًا في الصور الحاسوبية. + +**مثال برمجي** + +واجهة `Buffer` التي تضمن الوظائف الأساسية للمخزن. + +```java +/** + * Buffer interface. + */ +public interface Buffer { + + /** + * Clear the pixel in (x, y). + * + * @param x X coordinate + * @param y Y coordinate + */ + void clear(int x, int y); + + /** + * Draw the pixel in (x, y). + * + * @param x X coordinate + * @param y Y coordinate + */ + void draw(int x, int y); + + /** + * Clear all the pixels. + */ + void clearAll(); + + /** + * Get all the pixels. + * + * @return pixel list + */ + Pixel[] getPixels(); + +} +``` + +إحدى تطبيقات واجهة `Buffer`. + + +```java +/** + * FrameBuffer implementation class. + */ +public class FrameBuffer implements Buffer { + + public static final int WIDTH = 10; + public static final int HEIGHT = 8; + + private final Pixel[] pixels = new Pixel[WIDTH * HEIGHT]; + + public FrameBuffer() { + clearAll(); + } + + @Override + public void clear(int x, int y) { + pixels[getIndex(x, y)] = Pixel.WHITE; + } + + @Override + public void draw(int x, int y) { + pixels[getIndex(x, y)] = Pixel.BLACK; + } + + @Override + public void clearAll() { + Arrays.fill(pixels, Pixel.WHITE); + } + + @Override + public Pixel[] getPixels() { + return pixels; + } + + private int getIndex(int x, int y) { + return x + WIDTH * y; + } +} +``` + +```java +/** + * Pixel enum. Each pixel can be white (not drawn) or black (drawn). + */ +public enum Pixel { + + WHITE, BLACK; +} +``` + +`Scene` representa la escena del juego en la que ya se ha renderizado el búfer actual. + +```java +/** + * Scene class. Render the output frame. + */ +@Slf4j +public class Scene { + + private final Buffer[] frameBuffers; + + private int current; + + private int next; + + /** + * Constructor of Scene. + */ + public Scene() { + frameBuffers = new FrameBuffer[2]; + frameBuffers[0] = new FrameBuffer(); + frameBuffers[1] = new FrameBuffer(); + current = 0; + next = 1; + } + + /** + * Draw the next frame. + * + * @param coordinateList list of pixels of which the color should be black + */ + public void draw(List> coordinateList) { + LOGGER.info("Start drawing next frame"); + LOGGER.info("Current buffer: " + current + " Next buffer: " + next); + frameBuffers[next].clearAll(); + coordinateList.forEach(coordinate -> { + var x = coordinate.getKey(); + var y = coordinate.getValue(); + frameBuffers[next].draw(x, y); + }); + LOGGER.info("Swap current and next buffer"); + swap(); + LOGGER.info("Finish swapping"); + LOGGER.info("Current buffer: " + current + " Next buffer: " + next); + } + + public Buffer getBuffer() { + LOGGER.info("Get current buffer: " + current); + return frameBuffers[current]; + } + + private void swap() { + current = current ^ next; + next = current ^ next; + current = current ^ next; + } + +} +``` + +```java +public static void main(String[] args) { + final var scene = new Scene(); + var drawPixels1 = List.of(new MutablePair<>(1, 1), new MutablePair<>(5, 6), new MutablePair<>(3, 2)); + scene.draw(drawPixels1); + var buffer1 = scene.getBuffer(); + printBlackPixelCoordinate(buffer1); + + var drawPixels2 = List.of(new MutablePair<>(3, 7), new MutablePair<>(6, 1)); + scene.draw(drawPixels2); + var buffer2 = scene.getBuffer(); + printBlackPixelCoordinate(buffer2); +} + +private static void printBlackPixelCoordinate(Buffer buffer) { + StringBuilder log = new StringBuilder("Black Pixels: "); + var pixels = buffer.getPixels(); + for (var i = 0; i < pixels.length; ++i) { + if (pixels[i] == Pixel.BLACK) { + var y = i / FrameBuffer.WIDTH; + var x = i % FrameBuffer.WIDTH; + log.append(" (").append(x).append(", ").append(y).append(")"); + } + } + LOGGER.info(log.toString()); +} +``` + +مخرجات وحدة التحكم + + +```text +[main] INFO com.iluwatar.doublebuffer.Scene - Start drawing next frame +[main] INFO com.iluwatar.doublebuffer.Scene - Current buffer: 0 Next buffer: 1 +[main] INFO com.iluwatar.doublebuffer.Scene - Swap current and next buffer +[main] INFO com.iluwatar.doublebuffer.Scene - Finish swapping +[main] INFO com.iluwatar.doublebuffer.Scene - Current buffer: 1 Next buffer: 0 +[main] INFO com.iluwatar.doublebuffer.Scene - Get current buffer: 1 +[main] INFO com.iluwatar.doublebuffer.App - Black Pixels: (1, 1) (3, 2) (5, 6) +[main] INFO com.iluwatar.doublebuffer.Scene - Start drawing next frame +[main] INFO com.iluwatar.doublebuffer.Scene - Current buffer: 1 Next buffer: 0 +[main] INFO com.iluwatar.doublebuffer.Scene - Swap current and next buffer +[main] INFO com.iluwatar.doublebuffer.Scene - Finish swapping +[main] INFO com.iluwatar.doublebuffer.Scene - Current buffer: 0 Next buffer: 1 +[main] INFO com.iluwatar.doublebuffer.Scene - Get current buffer: 0 +[main] INFO com.iluwatar.doublebuffer.App - Black Pixels: (6, 1) (3, 7) +``` + +## مخطط الفئات + +![alt text](./etc/double-buffer.urm.png "مخطط فئة نمط المخزن المؤقت المزدوج") + +## القابلية للتطبيق + +هذا النمط هو أحد الأنماط التي ستعرف متى تحتاج إليها. إذا كان لديك نظام يفتقر إلى المخزن المؤقت المزدوج، فمن المحتمل أن يبدو بشكل غير صحيح مرئيًا (تمزق الصورة، إلخ) أو سيعمل بشكل غير صحيح. ولكن قول "ستعرف متى تحتاج إليه" لا يعطي الكثير من التوضيح. بشكل أكثر تحديدًا، هذا النمط مناسب عندما يكون كل هذا صحيحًا: + +- لدينا حالة يتم تعديلها بشكل تدريجي. +- يمكن الوصول إلى نفس الحالة في منتصف التعديل. +- نريد تجنب أن يرى الكود الذي يصل إلى الحالة العمل الجاري. +- نريد أن نتمكن من قراءة الحالة دون الحاجة إلى الانتظار أثناء الكتابة. + +## المصادر + +* [Game Programming Patterns - Double Buffer](http://gameprogrammingpatterns.com/double-buffer.html) + diff --git a/localization/ar/double-buffer/etc/double-buffer.urm.png b/localization/ar/double-buffer/etc/double-buffer.urm.png new file mode 100644 index 000000000000..072ec4dad8be Binary files /dev/null and b/localization/ar/double-buffer/etc/double-buffer.urm.png differ diff --git a/localization/ar/embedded-value/README.md b/localization/ar/embedded-value/README.md new file mode 100644 index 000000000000..c147fef4edab --- /dev/null +++ b/localization/ar/embedded-value/README.md @@ -0,0 +1,131 @@ +--- +title: Embedded Value +shortTitle: Embedded Value +category: Structural +language: ar +tag: + - Data Access + - Enterprise Application Pattern +--- + +## معروف أيضًا باسم + +التخصيص المدمج، المُركب + +## الهدف + +العديد من الكائنات الصغيرة تكون منطقية في نظام البرمجة الكائنية ولا تكون منطقية كجداول في قاعدة بيانات. القيمة المدمجة تخصيص قيم كائن إلى حقول سجل الكائن المالك. + +## الشرح + +مثال من الواقع + +> بعض الأمثلة تشمل الكائنات النقدية والفترات الزمنية. على الرغم من أن التفكير الافتراضي هو تخزين كائن كجدول، إلا أنه لا أحد في عقله السليم يرغب في جدول للقيم النقدية. +> مثال آخر هو الطلبات عبر الإنترنت التي تحتوي على عنوان الشحن مثل الشارع، المدينة، الدولة. نقوم بتخصيص هذه القيم من كائن عنوان الشحن إلى حقول سجل كائن الطلب. + +بكلمات بسيطة + +> يسمح نمط القيم المدمجة بتخصيص كائن لعدة حقول في جدول كائن آخر. + +**مثال برمجي** + +لنأخذ مثالًا من طلب عبر الإنترنت حيث لدينا تفاصيل العنصر المطلوب وعنوان الشحن. لدينا +عنوان الشحن مدمج في كائن الطلب. ولكن في قاعدة البيانات نقوم بتخصيص قيم عنوان الشحن في سجل الطلب بدلاً من إنشاء جدول منفصل لعنوان الشحن واستخدام مفتاح خارجي للإشارة إلى كائن الطلب. + +أولاً، لدينا كائنات `Order` و `ShippingAddress`. + + +```java +public class Order { + + private int id; + private String item; + private String orderedBy; + private ShippingAddress ShippingAddress; + + public Order(String item, String orderedBy, ShippingAddress ShippingAddress) { + this.item = item; + this.orderedBy = orderedBy; + this.ShippingAddress = ShippingAddress; + } +} +``` + +```java +public class ShippingAddress { + + private String city; + private String state; + private String pincode; + + public ShippingAddress(String city, String state, String pincode) { + this.city = city; + this.state = state; + this.pincode = pincode; + } +} +``` + +الآن، علينا إنشاء جدول واحد فقط للطلب مع الحقول الخاصة بسمات عنوان الشحن. + + +```Sql +CREATE TABLE Orders (Id INT AUTO_INCREMENT, item VARCHAR(50) NOT NULL, orderedBy VARCHAR(50) city VARCHAR(50), state VARCHAR(50), pincode CHAR(6) NOT NULL, PRIMARY KEY(Id)) +``` + +أثناء إجراء الاستفسارات والإدخالات في قاعدة البيانات، نقوم بتغليف وفك تغليف تفاصيل عناوين الشحن. + + +```java +final String INSERT_ORDER = "INSERT INTO Orders (item, orderedBy, city, state, pincode) VALUES (?, ?, ?, ?, ?)"; + +public boolean insertOrder(Order order) throws Exception { + var insertOrder = new PreparedStatement(INSERT_ORDER); + var address = order.getShippingAddress(); + conn.setAutoCommit(false); + insertIntoOrders.setString(1, order.getItem()); + insertIntoOrders.setString(2, order.getOrderedBy()); + insertIntoOrders.setString(3, address.getCity()); + insertIntoOrders.setString(4, address.getState()); + insertIntoOrders.setString(5, address.getPincode()); + + var affectedRows = insertIntoOrders.executeUpdate(); + if(affectedRows == 1){ + Logger.info("Inserted successfully"); + }else{ + Logger.info("Couldn't insert " + order); + } +} +``` + +## مخطط الفئات + +![alt text](./etc/embedded-value.urm.png "مخطط فئة القيمة المدمجة") + +## القابلية للتطبيق + +استخدم نمط القيمة المدمجة عندما: + +* تكون العديد من الكائنات الصغيرة ذات معنى في نظام OO ولكن ليس لها معنى كجداول في قاعدة بيانات. +* الحالات الأبسط للقيمة المدمجة هي الكائنات ذات القيم الواضحة والبسيطة مثل المال ونطاق التواريخ. +* إذا كنت تقوم بربط إلى مخطط موجود، يمكنك استخدام هذا النمط عندما تحتوي إحدى الجداول على بيانات ترغب في تقسيمها إلى أكثر من كائن في الذاكرة. قد يحدث هذا عندما ترغب في استخراج بعض السلوك في نموذج الكائنات. +* في معظم الحالات، ستستخدم القيمة المدمجة فقط في كائن مرجعي عندما تكون العلاقة بينهما ذات قيمة واحدة في كلا الطرفين (علاقة واحد إلى واحد). + +## الدروس التعليمية + +* [Dzone](https://dzone.com/articles/practical-php-patterns/practical-php-patterns-3) +* [Ram N Java](https://ramj2ee.blogspot.com/2013/08/embedded-value-design-pattern.html) +* [Five's Weblog](https://powerdream5.wordpress.com/2007/10/09/embedded-value/) + +## العواقب + +* الميزة الكبرى للقيمة المدمجة هي أنها تسمح بإجراء استفسارات SQL ضد قيم الكائن التابع. +* الكائن ذو القيمة المدمجة ليس له سلوك استمرارية. +* عند استخدام هذا، يجب أن تكون حذرًا من أن أي تغيير في التابع سيجعل المالك يعتبره "متسخًا" — وهو ما لا يمثل مشكلة مع الكائنات ذات القيمة التي يتم استبدالها في المالك. +* مشكلة أخرى هي التحميل والحفظ. إذا كنت تقوم بتحميل ذاكرة الكائن المدمج فقط عندما تقوم بتحميل المالك، فهذا حجة لحفظ كلاهما في نفس الجدول. +* قضية أخرى هي ما إذا كنت ترغب في الوصول إلى بيانات الكائنات المدمجة بشكل منفصل عبر SQL. قد يكون هذا مهمًا إذا كنت تقوم بإعداد تقارير عبر SQL وليس لديك قاعدة بيانات منفصلة للتقارير. + +## الائتمان + +* [Fowler, Martin - Patterns of enterprise application architecture-Addison-Wesley](https://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420) +* [Ram N Java](https://ramj2ee.blogspot.com/2013/08/embedded-value-design-pattern.html) diff --git a/localization/ar/embedded-value/etc/embedded-value.urm.png b/localization/ar/embedded-value/etc/embedded-value.urm.png new file mode 100644 index 000000000000..52d3ffb62352 Binary files /dev/null and b/localization/ar/embedded-value/etc/embedded-value.urm.png differ diff --git a/localization/ar/event-aggregator/README.md b/localization/ar/event-aggregator/README.md new file mode 100644 index 000000000000..03eae11fbe3c --- /dev/null +++ b/localization/ar/event-aggregator/README.md @@ -0,0 +1,167 @@ +--- +title: Event Aggregator +shortTitle: Event Aggregator +category: Structural +language: ar +tag: + - Reactive +--- + +## الاسم + +مجمع الأحداث + +## النية + +قد يصبح النظام الذي يحتوي على العديد من الكائنات معقدًا عندما يريد العميل الاشتراك في الأحداث. يجب على العميل +البحث والتسجيل في +كل كائن على حدة، وإذا كان كل كائن يحتوي على العديد من الأحداث فإن كل حدث يتطلب اشتراكًا +منفصلًا. يعمل مجمع الأحداث كمصدر واحد +للأحداث للعديد من الكائنات. يقوم بالتسجيل في جميع الأحداث للكائنات المتعددة مما يسمح للعملاء +بالتسجيل فقط مع المجمع. + +## الشرح + +مثال واقعي + +> يجلس الملك جوفري على عرش الحديد ويحكم الممالك السبع في وينترفل. يحصل على معظم معلوماته الهامة من يد الملك، +> وهو ثاني أقوى شخص في المملكة. يد الملك لديها العديد من المستشارين المقربين الذين يوفرون له معلومات هامة حول الأحداث التي تحدث في المملكة. + +بكلمات بسيطة + +> مجمع الأحداث هو وسيط للأحداث يقوم بجمع الأحداث من مصادر متعددة وتقديمها للمراقبين المسجلين. + +**مثال برمجي** + +في مثالنا البرمجي، نعرض تنفيذ نمط مجمع الأحداث. بعض الكائنات +هي مستمعون للأحداث، وبعضها الآخر هو مرسلو أحداث، والمجمع للأحداث يقوم بكلتا الوظيفتين. + + +```java +public interface EventObserver { + void onEvent(Event e); +} + +public abstract class EventEmitter { + + private final Map> observerLists; + + public EventEmitter() { + observerLists = new HashMap<>(); + } + + public final void registerObserver(EventObserver obs, Event e) { + ... + } + + protected void notifyObservers(Event e) { + ... + } +} +``` + +`KingJoffrey` يستمع إلى أحداث `KingsHand`. + + +```java +@Slf4j +public class KingJoffrey implements EventObserver { + @Override + public void onEvent(Event e) { + LOGGER.info("Received event from the King's Hand: {}", e.toString()); + } +} +``` + +`ReyMano` يستمع إلى الأحداث من مرؤوسيه `LordBaelish`، `LordVarys` و `Scout`. +ما يسمعه منهم، ينقله إلى "الملك جوفري". + + +```java +public class KingsHand extends EventEmitter implements EventObserver { + + public KingsHand() { + } + + public KingsHand(EventObserver obs, Event e) { + super(obs, e); + } + + @Override + public void onEvent(Event e) { + notifyObservers(e); + } +} +``` + +على سبيل المثال، `LordVarys` يجد خائنًا كل يوم أحد ويقوم بإبلاغ `KingsHand`. + + +```java +@Slf4j +public class LordVarys extends EventEmitter implements EventObserver { + @Override + public void timePasses(Weekday day) { + if (day == Weekday.SATURDAY) { + notifyObservers(Event.TRAITOR_DETECTED); + } + } +} +``` + +الجزء التالي يوضح كيفية بناء وربط الكائنات. + + +```java + var kingJoffrey = new KingJoffrey(); + + var kingsHand = new KingsHand(); + kingsHand.registerObserver(kingJoffrey, Event.TRAITOR_DETECTED); + kingsHand.registerObserver(kingJoffrey, Event.STARK_SIGHTED); + kingsHand.registerObserver(kingJoffrey, Event.WARSHIPS_APPROACHING); + kingsHand.registerObserver(kingJoffrey, Event.WHITE_WALKERS_SIGHTED); + + var varys = new LordVarys(); + varys.registerObserver(kingsHand, Event.TRAITOR_DETECTED); + varys.registerObserver(kingsHand, Event.WHITE_WALKERS_SIGHTED); + + var scout = new Scout(); + scout.registerObserver(kingsHand, Event.WARSHIPS_APPROACHING); + scout.registerObserver(varys, Event.WHITE_WALKERS_SIGHTED); + + var baelish = new LordBaelish(kingsHand, Event.STARK_SIGHTED); + + var emitters = List.of( + kingsHand, + baelish, + varys, + scout + ); + + Arrays.stream(Weekday.values()) + .>map(day -> emitter -> emitter.timePasses(day)) + .forEachOrdered(emitters::forEach); +``` + +الناتج في وحدة التحكم بعد تنفيذ المثال. + +``` +18:21:52.955 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: Warships approaching +18:21:52.960 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: White walkers sighted +18:21:52.960 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: Stark sighted +18:21:52.960 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: Traitor detected +``` + +## قابلية الاستخدام + +استخدم نمط "مجمّع الأحداث" عندما + +* يعد مجمّع الأحداث خيارًا جيدًا عندما يكون لديك العديد من الكائنات التي تعد مصادر محتملة للأحداث. بدلاً من جعل المراقب يتعامل مع التسجيل مع كل منها، يمكنك مركزية منطق التسجيل في مجمّع الأحداث. بالإضافة إلى تبسيط التسجيل، يبسط مجمّع الأحداث أيضًا مشكلات إدارة الذاكرة في استخدام المراقبين. + +## الأنماط المتعلقة + +* [Observer](https://java-design-patterns.com/patterns/observer/) + +## الاعتمادات + +* [مارتن فاولر - مجمّع الأحداث](http://martinfowler.com/eaaDev/EventAggregator.html) diff --git a/localization/ar/event-aggregator/etc/classes.png b/localization/ar/event-aggregator/etc/classes.png new file mode 100644 index 000000000000..295719ea3712 Binary files /dev/null and b/localization/ar/event-aggregator/etc/classes.png differ diff --git a/localization/ar/extension-objects/README.md b/localization/ar/extension-objects/README.md new file mode 100644 index 000000000000..0f96c8a0a516 --- /dev/null +++ b/localization/ar/extension-objects/README.md @@ -0,0 +1,149 @@ +--- +title: Extension objects +shortTitle: Extension objects +category: Behavioral +language: ar +tag: + - Extensibility +--- + +# نمط كائنات التوسيع (Extension Objects Pattern) + +## الهدف +التنبؤ بأنه يجب توسيع واجهة كائن ما في المستقبل. يتم تعريف الواجهات الإضافية من خلال كائنات التوسيع (Extension objects). + +## الشرح +مثال واقعي + +> افترض أنك تطور لعبة تعتمد على Java لعميل، وأثناء عملية التطوير، يُقترح عليك إضافة وظائف جديدة. يسمح لك نمط كائنات التوسيع بتكييف برنامجك مع التغييرات غير المتوقعة مع الحد الأدنى من إعادة الهيكلة، خاصة عند دمج وظائف إضافية في مشروعك. + +ببساطة + +> يتم استخدام نمط كائنات التوسيع لإضافة وظائف ديناميكيًا إلى الكائنات دون تعديل فئاتها الرئيسية. إنه نمط تصميم سلوكي يستخدم لإضافة وظائف جديدة إلى الفئات والكائنات الموجودة داخل البرنامج. يوفر هذا النمط للمبرمجين القدرة على تمديد/تعديل وظائف الفئات دون الحاجة إلى إعادة هيكلة الكود المصدر الحالي. + +تقول ويكيبيديا + +> في البرمجة الكائنية التوجه، يعتبر نمط كائنات التوسيع نمط تصميم يضاف إلى كائن بعد أن يتم تجميع الكائن الأصلي. الكائن المعدل غالبًا ما يكون فئة أو نموذجًا أو نوعًا. تعتبر أنماط كائنات التوسيع سمة من سمات بعض لغات البرمجة الكائنية التوجه. لا يوجد فرق نحوي بين استدعاء طريقة توسيع وطريقة معرفة في تعريف النوع. + +**مثال برمجي** + +الهدف من استخدام نمط كائنات التوسيع (Extension objects) هو تنفيذ ميزات/وظائف جديدة دون الحاجة إلى إعادة هيكلة كل فئة. +توضح الأمثلة التالية استخدام هذا النمط في فئة "العدو" التي تمتد من "الكيان" داخل لعبة: + +الفئة الرئيسية للتطبيق التي يتم تشغيل برنامجنا منها. + + +```java +public class App { + public static void main(String[] args) { + Entity enemy = new Enemy("Enemy"); + checkExtensionsForEntity(enemy); + } + + private static void checkExtensionsForEntity(Entity entity) { + Logger logger = Logger.getLogger(App.class.getName()); + String name = entity.getName(); + Function func = (e) -> () -> logger.info(name + " without " + e); + + String extension = "EnemyExtension"; + Optional.ofNullable(entity.getEntityExtension(extension)) + .map(e -> (EnemyExtension) e) + .ifPresentOrElse(EnemyExtension::extendedAction, func.apply(extension)); + } +} +``` +فئة العدو مع الإجراءات الأولية والتوسعات. + + +```java +class Enemy extends Entity { + public Enemy(String name) { + super(name); + } + + @Override + protected void performInitialAction() { + super.performInitialAction(); + System.out.println("Enemy wants to attack you."); + } + + @Override + public EntityExtension getEntityExtension(String extensionName) { + if (extensionName.equals("EnemyExtension")) { + return Optional.ofNullable(entityExtension).orElseGet(EnemyExtension::new); + } + return super.getEntityExtension(extensionName); + } +} +``` + +فئة EnemyExtension مع إعادة كتابة طريقة extendAction(). + + +```java +class EnemyExtension implements EntityExtension { + @Override + public void extendedAction() { + System.out.println("Enemy has advanced towards you!"); + } +} +``` + +فئة الكائن التي سيتم توسيعها بواسطة العدو. + + +```java +class Entity { + private String name; + protected EntityExtension entityExtension; + + public Entity(String name) { + this.name = name; + performInitialAction(); + } + + protected void performInitialAction() { + System.out.println(name + " performs the initial action."); + } + + public EntityExtension getEntityExtension(String extensionName) { + return null; + } + + public String getName() { + return name; + } +} +``` +واجهة `EntityExtension` التي ستستخدم `EnemyExtension`. + + +```java +interface EntityExtension { + void extendedAction(); +} +``` +إخراج البرنامج: + + +```markdown +Enemy performs the initial action. +Enemy wants to attack you. +Enemy has advanced towards you! +``` +في هذا المثال، يسمح نمط "كائنات التمديد" (Extension Objects) لكي يقوم الكائن العدو بتنفيذ إجراءات مبدئية فريدة وإجراءات متقدمة عند تطبيق التمديدات الخاصة. يوفر هذا النمط مرونة وقابلية تمديد لقاعدة الشيفرة مع تقليل الحاجة إلى إجراء تغييرات كبيرة في الشيفرة. + +## مخطط الفئات +![Extension_objects](./etc/extension_obj.png "Extension objects") + +## قابلية التطبيق +استخدم نمط "كائنات التمديد" (Extension objects) عندما: + +* تحتاج إلى دعم إضافة واجهات جديدة أو غير متوقعة إلى فئات موجودة ولا تريد التأثير على العملاء الذين لا يحتاجون إلى هذه الواجهة الجديدة. تتيح لك كائنات التمديد الاحتفاظ بالعمليات ذات الصلة معًا عن طريق تعريفها في فئة منفصلة. +* فئة تمثل تجريدًا رئيسيًا تؤدي وظائف مختلفة لعملاء مختلفين. يجب أن يكون عدد الوظائف التي يمكن أن تؤديها الفئة غير محدود. من الضروري الحفاظ على التجريد الرئيسي نفسه. على سبيل المثال، يبقى كائن العميل كائن عميل رغم أن الأنظمة الفرعية المختلفة قد تراها بطريقة مختلفة. +* يجب أن تكون الفئة قابلة للتمديد بسلوكيات جديدة دون الحاجة إلى تصنيفها منها. + +## أمثلة من العالم الحقيقي + +* [OpenDoc](https://en.wikipedia.org/wiki/OpenDoc) +* [ربط الكائنات وإدماجها](https://en.wikipedia.org/wiki/Object_Linking_and_Embedding) diff --git a/localization/ar/extension-objects/etc/extension_obj.png b/localization/ar/extension-objects/etc/extension_obj.png new file mode 100644 index 000000000000..a2b750e9dedd Binary files /dev/null and b/localization/ar/extension-objects/etc/extension_obj.png differ diff --git a/localization/ar/facade/README.md b/localization/ar/facade/README.md new file mode 100644 index 000000000000..99fa3bd04e9f --- /dev/null +++ b/localization/ar/facade/README.md @@ -0,0 +1,216 @@ +--- +title: Facade +shortTitle: Facade +category: Structural +language: ar +tag: + - Gang Of Four + - Decoupling +--- + +## الهدف + +توفير واجهة موحدة لمجموعة من واجهات النظام الفرعي. تقوم الواجهة البسيطة بتحديد واجهة تسهل استخدام النظام الفرعي. + +## الشرح + +مثال واقعي + +> كيف يعمل منجم الذهب؟ "حسنًا، ينزل العمال لاستخراج الذهب!" تقول. هذا ما تعتقده لأنك تستخدم واجهة بسيطة يوفرها منجم الذهب، ولكن من الداخل يجب أن يقوم بالكثير من الأشياء لتحقيق ذلك. هذه الواجهة البسيطة للنظام الفرعي المعقد هي الواجهة الأمامية. + +بإيجاز + +> يوفر نمط الواجهة الأمامية واجهة مبسطة لنظام فرعي معقد. + +تقول ويكيبيديا + +> الواجهة الأمامية هي كائن يوفر واجهة مبسطة لجسم من الكود الأكبر، مثل مكتبة الفصول. + +**مثال برمجي** + +لنأخذ مثال منجم الذهب. هنا لدينا تسلسل عمال الأقزام في المنجم. أولاً، لدينا فئة أساسية `DwarvenMineWorker`: + + +```java + +@Slf4j +public abstract class DwarvenMineWorker { + + public void goToSleep() { + LOGGER.info("{} goes to sleep.", name()); + } + + public void wakeUp() { + LOGGER.info("{} wakes up.", name()); + } + + public void goHome() { + LOGGER.info("{} goes home.", name()); + } + + public void goToMine() { + LOGGER.info("{} goes to the mine.", name()); + } + + private void action(Action action) { + switch (action) { + case GO_TO_SLEEP -> goToSleep(); + case WAKE_UP -> wakeUp(); + case GO_HOME -> goHome(); + case GO_TO_MINE -> goToMine(); + case WORK -> work(); + default -> LOGGER.info("Undefined action"); + } + } + + public void action(Action... actions) { + Arrays.stream(actions).forEach(this::action); + } + + public abstract void work(); + + public abstract String name(); + + enum Action { + GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK + } +} +``` + +ثم لدينا الفئات المحددة للأقزام `DwarvenTunnelDigger`، `DwarvenGoldDigger` و `DwarvenCartOperator`: + + +```java +@Slf4j +public class DwarvenTunnelDigger extends DwarvenMineWorker { + + @Override + public void work() { + LOGGER.info("{} creates another promising tunnel.", name()); + } + + @Override + public String name() { + return "Dwarven tunnel digger"; + } +} + +@Slf4j +public class DwarvenGoldDigger extends DwarvenMineWorker { + + @Override + public void work() { + LOGGER.info("{} digs for gold.", name()); + } + + @Override + public String name() { + return "Dwarf gold digger"; + } +} + +@Slf4j +public class DwarvenCartOperator extends DwarvenMineWorker { + + @Override + public void work() { + LOGGER.info("{} moves gold chunks out of the mine.", name()); + } + + @Override + public String name() { + return "Dwarf cart operator"; + } +} + +``` + +لإدارة جميع هؤلاء العمال في منجم الذهب، لدينا `FachadaDwarvenGoldmine`: + + +```java +public class DwarvenGoldmineFacade { + + private final List workers; + + public DwarvenGoldmineFacade() { + workers = List.of( + new DwarvenGoldDigger(), + new DwarvenCartOperator(), + new DwarvenTunnelDigger()); + } + + public void startNewDay() { + makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE); + } + + public void digOutGold() { + makeActions(workers, DwarvenMineWorker.Action.WORK); + } + + public void endDay() { + makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP); + } + + private static void makeActions(Collection workers, + DwarvenMineWorker.Action... actions) { + workers.forEach(worker -> worker.action(actions)); + } +} +``` + +الآن سنستخدم الواجهة: + + +```java +var facade = new DwarvenGoldmineFacade(); +facade.startNewDay(); +facade.digOutGold(); +facade.endDay(); +``` + +إخراج البرنامج: + + +```java +// Dwarf gold digger wakes up. +// Dwarf gold digger goes to the mine. +// Dwarf cart operator wakes up. +// Dwarf cart operator goes to the mine. +// Dwarven tunnel digger wakes up. +// Dwarven tunnel digger goes to the mine. +// Dwarf gold digger digs for gold. +// Dwarf cart operator moves gold chunks out of the mine. +// Dwarven tunnel digger creates another promising tunnel. +// Dwarf gold digger goes home. +// Dwarf gold digger goes to sleep. +// Dwarf cart operator goes home. +// Dwarf cart operator goes to sleep. +// Dwarven tunnel digger goes home. +// Dwarven tunnel digger goes to sleep. +``` + +## مخطط الفئات + +![alt text](./etc/facade.urm.png "مخطط فئة نمط الواجهة") + +## قابلية التطبيق + +استخدم نمط الواجهة عندما: + +* ترغب في توفير واجهة بسيطة إلى نظام فرعي معقد. غالبًا ما تصبح الأنظمة الفرعية أكثر تعقيدًا مع تطورها. معظم الأنماط، عند تطبيقها، تؤدي إلى المزيد من الفئات الأصغر. هذا يجعل النظام الفرعي أكثر قابلية لإعادة الاستخدام وأسهل في التخصيص، ولكن أيضًا يصبح أكثر صعوبة في الاستخدام للعملاء الذين لا يحتاجون إلى تخصيصه. يمكن أن توفر الواجهة عرضًا بسيطًا افتراضيًا للنظام الفرعي الذي يكفي لمعظم العملاء. فقط العملاء الذين يحتاجون إلى مزيد من التخصيص سيضطرون للنظر إلى ما وراء الواجهة. +* هناك العديد من الاعتمادات بين العملاء وفئات تنفيذ التجريد. إدخال واجهة لفصل النظام الفرعي عن العملاء والأنظمة الفرعية الأخرى، مما يعزز الاستقلالية وقابلية النقل للنظام الفرعي. +* ترغب في تقسيم أنظمتك الفرعية. استخدم واجهة لتعريف نقطة دخول إلى كل مستوى من النظام الفرعي. إذا كانت الأنظمة الفرعية تعتمد على بعضها البعض، يمكنك تبسيط الاعتمادات بينها من خلال جعلها تتواصل مع بعضها البعض فقط من خلال واجهاتها. + +## الدروس التعليمية + +* [DigitalOcean](https://www.digitalocean.com/community/tutorials/facade-design-pattern-in-java) + +* [Refactoring Guru](https://refactoring.guru/design-patterns/facade) +* [GeekforGeeks](https://www.geeksforgeeks.org/facade-design-pattern-introduction/) +* [Tutorialspoint](https://www.tutorialspoint.com/design_pattern/facade_pattern.htm) + +## الاعتمادات + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) diff --git a/localization/ar/facade/etc/facade.urm.png b/localization/ar/facade/etc/facade.urm.png new file mode 100644 index 000000000000..8e3ec7aca45e Binary files /dev/null and b/localization/ar/facade/etc/facade.urm.png differ diff --git a/localization/ar/factory/README.md b/localization/ar/factory/README.md new file mode 100644 index 000000000000..5241065e3590 --- /dev/null +++ b/localization/ar/factory/README.md @@ -0,0 +1,140 @@ +--- +title: Factory +shortTitle: Factory +category: Creational +language: ar +tag: + - Gang of Four +--- + +## أيضًا معروف بـ + +* المصنع البسيط +* طريقة المصنع الثابتة + +## الهدف + +توفير طريقة ثابتة محاطة في فئة تسمى المصنع (Factory)، لإخفاء منطق التنفيذ وجعل شفرة العميل تركز على الاستخدام بدلاً من تهيئة الكائنات الجديدة. + +## الشرح + +مثال من الحياة الواقعية + +> تخيل كيميائيًا على وشك تصنيع العملات. يجب أن يكون الكيميائي قادرًا على إنشاء عملات ذهبية وكذلك عملات نحاسية، ويجب أن يكون من الممكن التبديل بينهما دون تعديل الكود المصدري الحالي. يجعل نمط المصنع هذا ممكنًا من خلال توفير طريقة بناء ثابتة يمكن استدعاؤها مع المعلمات ذات الصلة. + +تقول ويكيبيديا + +> المصنع (Factory) هو كائن لإنشاء كائنات أخرى: بشكل رسمي، المصنع هو دالة أو طريقة تُرجع كائنات من نموذج أو فئة متغيرة. + +**مثال برمجي** + +لدينا واجهة عملة `Coin` واثنان من تطبيقات العملة: عملة ذهبية `GoldCoin` وعملة نحاسية `CopperCoin`. + + +```java +public interface Coin { + String getDescription(); +} + +public class GoldCoin implements Coin { + + static final String DESCRIPTION = "This is a gold coin."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +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 constructor; +} +``` + +ثم لدينا الطريقة الثابتة للحصول على العملة `getCoin` لإنشاء كائنات العملة مغلفة داخل فئة المصنع `CoinFactory`. + + +```java +public class CoinFactory { + + public static Coin getCoin(CoinType type) { + return type.getConstructor().get(); + } +} +``` + +الآن في كود العميل يمكننا إنشاء أنواع مختلفة من العملات باستخدام فئة المصنع. + + +```java +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()); +``` + +### مخرجات البرنامج: + + +```java +The alchemist begins his work. +This is a copper coin. +This is a gold coin. +``` + +## المخطط البياني للفئات + +![alt text](./etc/factory.urm.png "Factory pattern diagrama de clases") + +## قابلية الاستخدام + +استخدم نمط المصنع (Factory) عندما يكون تركيزك على إنشاء الكائنات فقط دون القلق حول كيفية إنشائها وإدارتها. + +### المزايا + +* يسمح بجمع كل عمليات إنشاء الكائنات في مكان واحد وتجنب نشر الكلمة الأساسية 'new' عبر قاعدة الشيفرة. +* يُمكنك من كتابة شيفرة منخفضة الارتباط. من بين مزاياه الرئيسية: قابلية أفضل للاختبار، شيفرة سهلة الفهم، مكونات قابلة للاستبدال، قابلية التوسع، وميزات معزولة. + +### العيوب + +* قد يصبح الشيفرة أكثر تعقيدًا مما ينبغي. + +## أمثلة استخدام معروفة + +* [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--) + وأيضًا طرق مشابهة أخرى. + +## الأنماط المرتبطة + +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/) +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/) diff --git a/localization/ar/factory/etc/factory.urm.png b/localization/ar/factory/etc/factory.urm.png new file mode 100644 index 000000000000..4b3420792e06 Binary files /dev/null and b/localization/ar/factory/etc/factory.urm.png differ