الگوی سازنده یک الگوی مهندسی نرمافزار به منظور ایجاد اشیا می باشد. این الگو به منظور حل وجۀ دیگری از مشکل ساخت و تنظیم اشیا در برنامه نویسی معرفی شده است. مشکل بدین شرح است که گاهی نیاز است هنگام ساخت یک شی تعداد زیادی پارامتر را به سازندۀ ( constructor ) آن تحویل دهیم و این کار برنامه نویسی و همچنین خوانایی برنامه را کم میکند .
به منظور حل این مشکل از الگوی سازنده استفاده میکنیم. در این تکنیک به جای طراحی تعدادی سازنده ( constructor ) با تعداد زیادی پارامتر از یک شی دیگر استفاده میکنیم که کار پارامتردهی را به صورت مرحله به مرحله و خوانا تر انجام می دهد و در نهایت از نوع شی مورد نظر یک نمونه با تنظیمات خواسته شده را به ما تحویل میدهد.
معمولاً یک طراح در مسیر طراحی٬ ابتدا با الگوی روش کارخانه ( factory method ) شروع می کند سپس به الگوی کارخانه انتزای ( abstract factory ) یا الگوی نمونه ی اولیه ( prototype ) و یا سازنده ( builder ) متوصل میشود . معمولاً هنگامی به الگوی سازنده متوصل میشویم که در فرایند طراحی به انعطاف پذیری بیشتر نیاز پیدا میکنیم.
هدف از استفاده از این الگو این است که فرایند ساخت ( construction ) یک شی پیچیده را از کد آن شی object representation )) جدا کنیم.
سازنده ( buillder )
- یک رابط انتزاعی برای ساخت شی
سازنده ی پیاده سازی شده و واقعی ( concrete builder )
- یک پیاده سازی از رابط سازنده میباشد . یک شی از این نوع میتواند به عنوان یک سازنده برای شی مورد نظر عمل کند.
به مثال زیر توجه کنید
public class StreetMap {
private final Point origin;
private final Point destination;
private final Color waterColor;
private final Color landColor;
private final Color highTrafficColor;
private final Color mediumTrafficColor;
private final Color lowTrafficColor;
public static class Builder {
// Required parameters
private final Point origin;
private final Point destination;
// Optional parameters - initialize with default values
private Color waterColor = Color.BLUE;
private Color landColor = new Color(30, 30, 30);
private Color highTrafficColor = Color.RED;
private Color mediumTrafficColor = Color.YELLOW;
private Color lowTrafficColor = Color.GREEN;
public Builder(Point origin, Point destination) {
this.origin = origin;
this.destination = destination;
}
public Builder waterColor(Color color) {
waterColor = color;
return this;
}
public Builder landColor(Color color) {
landColor = color;
return this;
}
public Builder highTrafficColor(Color color) {
highTrafficColor = color;
return this;
}
public Builder mediumTrafficColor(Color color) {
mediumTrafficColor = color;
return this;
}
public Builder lowTrafficColor(Color color) {
lowTrafficColor = color;
return this;
}
public StreetMap build() {
return new StreetMap(this);
}
}
private StreetMap(Builder builder) {
// Required parameters
origin = builder.origin;
destination = builder.destination;
// Optional parameters
waterColor = builder.waterColor;
landColor = builder.landColor;
highTrafficColor = builder.highTrafficColor;
mediumTrafficColor = builder.mediumTrafficColor;
lowTrafficColor = builder.lowTrafficColor;
}
public static void main(String args[]) {
StreetMap map = new StreetMap.Builder(new Point(50, 50), new Point(100,
100)).landColor(Color.GRAY).waterColor(Color.BLUE.brighter())
.build();
}
}
کد های بالا با استفاده از الگوی سازنده در زبان جاوا نوشته شده است.
حالا به مثال پایین توجه کنید :
در این مثال 4 کلاس اصلی داریم که متدهای مشترکی دارند به اصطلاح بهشون product میگیم.
- EmployedMaleBuilder
- UnemployedMaleBuilder
- EmployedFemaleBuilder
- UnemployedFemaleBuilder
یک کلاس به اسم PersonDirector داریم که وظیفه اجرای متدهای مختلف یک کلاس خاص به ترتیب را دارد .
/**
* An extremely basic class for creating people objects
*/
class Person
{
public $employed;
public $gender;
const GENDER_MALE = "Male";
const GENDER_FEMALE = "Female";
}
/**
* All people builder should implement this interface
*/
interface PersonBuilderInterface
{
public function setGender();
public function setEmployed();
public function getResult();
}
/**
* builder to create an employed male
*/
class EmployedMaleBuilder implements PersonBuilderInterface
{
private $person;
public function __construct()
{
$this->person = new Person();
}
public function setGender()
{
$this->person->gender = Person::GENDER_MALE;
}
public function setEmployed()
{
$this->person->employed = true;
}
public function getResult()
{
return $this->person;
}
}
/**
* builder to create an unemployed male
*/
class UnemployedMaleBuilder implements PersonBuilderInterface
{
private $person;
public function __construct()
{
$this->person = new Person();
}
public function setGender()
{
$this->person->gender = Person::GENDER_MALE;
}
public function setEmployed()
{
$this->person->employed = false;
}
public function getResult()
{
return $this->person;
}
}
/**
* builder to create an employed female
*/
class EmployedFemaleBuilder implements PersonBuilderInterface
{
private $person;
public function __construct()
{
$this->person = new Person();
}
public function setGender()
{
$this->person->gender = Person::GENDER_FEMALE;
}
public function setEmployed()
{
$this->person->employed = true;
}
public function getResult()
{
return $this->person;
}
}
/**
* builder to create an unemployed female
*/
class UnemployedFemaleBuilder implements PersonBuilderInterface
{
private $person;
public function __construct()
{
$this->person = new Person();
}
public function setGender()
{
$this->person->gender = Person::GENDER_FEMALE;
}
public function setEmployed()
{
$this->person->employed = false;
}
public function getResult()
{
return $this->person;
}
}
/**
* The director class is part of the builder patter, the build method should be passed a builder.
* The build method should than call all of the builder methods and return a Person object
*/
class PersonDirector
{
public function build(PersonBuilderInterface $builder)
{
$builder->setGender();
$builder->setEmployed();
return $builder->getResult();
}
}
$director = new PersonDirector();
$employedMaleBuilder = new EmployedMaleBuilder();
$unemployedMaleBuilder = new UnemployedMaleBuilder();
$employedFemaleBuilder = new EmployedFemaleBuilder();
$unemployedFemaleBuilder = new UnemployedFemaleBuilder();
/**
* object(Person)#3 (2) {
* (
* ["employed"] => bool(true)
* ["gender"] => string(4) "Male"
* )
*/
$employedMale = $director->build($employedMaleBuilder);
/**
* object(Person)#5 (2) {
* (
* ["employed"] => bool(false)
* ["gender"] => string(4) "Male"
* )
*/
$unemployedMale = $director->build($unemployedMaleBuilder);
/**
* object(Person)#7 (2) {
* (
* ["employed"] => bool(true)
* ["gender"] => string(4) "Female"
* )
*/
$employedFemale = $director->build($employedFemaleBuilder);
/**
* object(Person)#11 (2) {
* (
* ["employed"] => bool(false)
* ["gender"] => string(4) "Female"
* )
*/
$unemployedFemale = $director->build($unemployedFemaleBuilder);
قاعده های دیزاین پترن builder
- هر builder ای (منظور همان کلاس های EmployedMaleBuilder و UnemployedMaleBuilder و …) که ایجاد می کنید باید متدهای مختلفی داشته باشند و هر متد آن فقط یه قسمتی از کد یا کانفیگ ما را انجام دهد .
- هر builder ای (منظور همان کلاس های EmployedMaleBuilder و UnemployedMaleBuilder و …) که ایجاد می کنید باید از اینترفیس مورد نظر implement شود .
- هر builder ای (منظور همان کلاس های EmployedMaleBuilder و UnemployedMaleBuilder و …) که ایجاد می کنید باید یک متد () getResult داشته باشد و تمام آبجکت آماده شده را بازگرداند .
- به جای اینکه متدهای داخل builder ها را خودمان مستقیم صدا بزنیم باید شی builder را ایجاد کنی و آن را به کلاس director خودمان پاس دهیم تا متدها داخل آن صدا زده شود .
- هر کلاس کلاس director باید یک متد build داشته باشد تا متدهای داخل کلاس های builder (منظور همان کلاس های EmployedMaleBuilder و UnemployedMaleBuilder و …) را صدا بزند
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید