Builder Design pattern
بسم الله الرحمن الرحيم
نكمل ما بدأناه بالحديث عن أكثر Design pattern استخداما في بيئة Android واليوم نتم الحديث عن Creational patterns بعد تكلمنا عن Singleton و dependency injection
اليوم سكون حديثنا عن Builder Design patterns
نقتبس التعريف من كتاب GoF
اقتباسThe builder pattern is used to create complex objects with constituent parts that must be created in the same order or using a specific algorithm. An external class controls the construction algorithm.
جميل جداً كما ذكر في التعريف إذ أننا سنقوم بتقسيم بناء Object إلى عدة method نبدء بالأساسية التي لا يمكن التعامل مع Object بدونها, ثم ننتقل إلى الاختيارية حتى نتم بناء Object على الوجه الذي نريد.
لنبدأ بمثال يوضح المشكلة .
لنفترض أننا نريد إنشاء class لفريق معين كالتالي :
public class Player {
private String name ;
private String team ;
private double height ;
private int salary ;
private String phone ;
private String twitterAccount ;
public Player(String name, String team, double height, int salary, String phone, String twitterAccount) {
this.name = name;
this.team = team;
this.height = height;
this.salary = salary;
this.phone = phone;
this.twitterAccount = twitterAccount;
}
}
نحن هنا نتعامل مع six class data member فقط فلو فرضنا أن لدينا 10 فسيكون شكل constructor رهيب جدا وفي هذا عدة مشاكل منها
أنك لن تستطيع تذكر أماكن data member في constructor مما يسبب في وضع البيانات في غير مكانها وستحصل على نتائج غريبة قد لا يصنفها compiler ك Error ولتلافي هذه المشكلة
سنستعرض أحد الحلول وهو Telescopin Design Pattern حيث سنقوم بكتابة شكل constructor فقط
public Player(String name, String team) {
this(name, team,0.0);
}
public Player(String name, String team, double height) {
this(name, team,height,0);
}
public Player(String name, String team, double height, int salary) {
this(name, team,height,salary,"");
}
public Player(String name, String team, double height, int salary, String phone) {
this(name, team,height,salary,phone,"");
}
public Player(String name, String team, double height, int salary, String phone, String twitterAccount) {
this.name = name;
this.team = team;
this.height = height;
this.salary = salary;
this.phone = phone;
this.twitterAccount = twitterAccount;
}
كما تلاحظ نبدأ بالمعلومات الأساسية التي لا يمكن الاستمرار بدونها ثم بعد ذلك نبدأ بتوفير البيانات في حال كانت لدينا أو نسند قيم افتراضية.
ولهذه الطريقة عيوبها أولا صعوبة قراءة code وأيضا صعوبة في كتابة client code (إنشاء object ), بالإضافة إلى أنك قد تجبر على كتابة parameters التي لا تريد كتابتها.
لهذه قد يكون استخدام Telescopin ليس الحل المناسب, لكن يوجد حل أخر لنأخذ فرصة في تجربته ألا وهو javaBeans Pattern , لنطبقه على نفس المثال السابق.
public Player() {}
public void setName(String name) {
this.name = name;
}
public void setTeam(String team) {
this.team = team;
}
public void setHeight(double height) {
this.height = height;
}
public void setSalary(int salary) {
this.salary = salary;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setTwitterAccount(String twitterAccount) {
this.twitterAccount = twitterAccount;
}
فكما ترى نبدأ ب constructor وبعد ذلك setters بعدد data members , وهذا الحل يحل بعض الإشكالات السابقة ويخلق إشكالات جديدة, فأولا سيكون إنشاء Object مرتبط بعدد كبير من method التي يجب استدعاؤها وتذكرها
بالإضافة إلى أنه لا يمكنك جعل class immutable, وليس thread safe, فتجازونا بعض إشكالات Telescopin ووقعنا في إشكالات أخرى ,فسنجمع بينهم في Patterm وهو Builder Design Pattern.
لنعيد كتابة constructor بإستخدام نفس المثال
public class Player {
private String name ;
private String team ;
private double height ;
private int salary ;
private String phone ;
private String twitterAccount ;
public static class Builder {
private final String name ;
private final String team ;
private double height = 0;
private int salary = 0;
private String phone = "";
private String twitterAccount = "";
public Builder(String name, String team) {
this.name = name;
this.team = team;
}
public Builder height(double height) {
this.height = height;
return this ;
}
public Builder salary(int salary) {
this.salary = salary;
return this ;
}
public Builder phone(String phone) {
this.phone = phone;
return this ;
}
public Builder twitterAccount(String twitterAccount) {
this.twitterAccount = twitterAccount;
return this ;
}
public Player build(){
return new Player(this);
}
}
public Player(Builder builder) {
name = builder.name;
team = builder.team;
height = builder.height;
salary = builder.salary;;
phone = builder.phone;;
twitterAccount = builder.twitterAccount;
}
}
في البداية قمنا ببناء inner class سميناه Builder حيث سنقوم بداخله ببناء Object الخاص بنا وبعد ذلك نرجعه عن طريق دالة build التي تقوم بعمل return ل object الذي قمنا ببناءه, نبدأ بالمتغيرات الأساسية في Object وهي التي كانت final ولا تأخذ قيم افتراضية, ثم الاختيارية التي قد نستخدمها فنستدعي method الخاصة بها, أو لا نستخدمها فنسند فيه القيم الافتراضية, فيكون شكل client كالتالي
Player player = new Player.Builder("Aziz", "Android")
.height(10.2)
.phone("0555555555")
.salary(100)
.build();
كما نلاحظ قمنا بكتابة client سهل القراءة وحتى الكتابة, ومرن وبسيط جدا.
اذا ف Builder Pattern خيار جيد جداً حينما يكون عدد Parameters ليس بالقليل ويكون فيه عدد من Parameters اختيارية
المراجع ومصادر :
التعليقات (0)
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !