بعنوان مثال دوم، به کد زیر رو که رفتار دو اتومبیل پورشه و مرسدس رو شبیه سازی میکنه، دقت کنید:
public class Porsche
{
public string Brand;
public System.Drawing.Color Color;
public Porsche(string brand, System.Drawing.Color color)
{
Brand = brand;
Color = color;
}
public Porsche(string brand)
{
Brand = brand;
}
public void Start()
{
}
public void Brake()
{
}
}
public class Mercedes
{
public string Brand;
public System.Drawing.Color Color;
public Mercedes(string brand, System.Drawing.Color color)
{
Brand = brand;
Color = color;
}
public Mercedes(string brand)
{
Brand = brand;
}
public Mercedes()
{
}
public void Start()
{
}
public void Brake()
{
}
}
بوی بد این کد رو می تونید استشمام کنید؟ این کد حاکی از نادیده گرفته شدن Object Oriented توسط برنامه نویس هستش. آستینها رو بالا بزنید و مرحله به مرحله کد رو پالایش کنید.
در مرحله اول، خصیصه های یک اتومبیل رو از دو کد فوق جدا می کنیم. برای اینکار، داخل یکی از دو کلاس فوق، Right Click کرده، گزینه Refactor رو انتخاب کنید. سپس Extract Interface رو انتخاب کنید. نام Interface رو به ICar تغییر بدید و مطمئن بشید که دو متود Start و Brake رو انتخاب کرده اید. حالا کلید OK رو بزنید. بدین ترتیب، Interface ای با دو متود فوق ایجاد میشه:
interface ICar
{
void Brake();
void Start();
}
و کلاس Porsche (با فرض اینکه در این کلاس Right-Click کرده ایم) از ICar مشتق میشه. حالا کلاس Mercedes رو بصورت دستی از همون ICar درایو کنید. از نظر منطقی اوضاع بسیار بهتر شد، اما هنوز بوی بد این کد آزار دهنده هستش.
در مرحله بعد، ابتدا ICar رو بدین شکل تغییر میدیم، زیرا مدل و رنگ، دو خصیصه یک اتومبیل هستن:
interface ICar
{
void Brake();
void Start();
string Brand { get; set; }
System.Drawing.Color Color { get; set; }
}
سپس دو کلاس فوق رو بگونه ای تغییر میدیم که دسترسی به دو متغیر عمومی فوق، کنترل شده باشه (در واقع از طریق Accessor ها در دسترس باشن). بدین ترتیب به کد زیر میرسیم:
interface ICar
{
void Brake();
void Start();
string Brand { get; set; }
System.Drawing.Color Color { get; set; }
}
public class Porsche : ICar
{
public string brand;
public System.Drawing.Color color;
public string Brand
{
get { return this.brand; }
set { this.brand = value; }
}
public System.Drawing.Color Color
{
get { return this.color; }
set { this.color = value; }
}
public Porsche(string brand, System.Drawing.Color color)
{
Brand = brand;
Color = color;
}
public Porsche(string brand)
{
Brand = brand;
}
public void Start()
{
}
public void Brake()
{
}
}
public class Mercedes : ICar
{
private string brand;
private System.Drawing.Color color;
public string Brand
{
get { return this.brand; }
set { this.brand = value; }
}
public System.Drawing.Color Color
{
get { return this.color; }
set { this.color = value; }
}
public Mercedes(string brand, System.Drawing.Color color)
{
Brand = brand;
Color = color;
}
public Mercedes(string brand)
{
Brand = brand;
}
public Mercedes()
{
}
public void Start()
{
}
public void Brake()
{
}
}
بسیار خوب. خیلی بهتر شد، اما هنوز آزاردهنده هستش. در این مرحله، کلاسی تحت عنوان Car ایجاد میکنم، و ICar رو در این کلاس پیاده سازی میکنم:
public class Car : ICar
{
private string brand;
private System.Drawing.Color color;
public Car(string brand, System.Drawing.Color color)
{
Brand = brand;
Color = color;
}
public Car()
{
}
public string Brand
{
get { return this.brand; }
set { this.brand = value; }
}
public System.Drawing.Color Color
{
get { return this.color; }
set { this.color = value; }
}
public virtual void Brake()
{
}
public virtual void Start()
{
}
}
و در نتیجه دو کلاس پورشه و مرسدس رو به این شکل تغییر میدم:
public class Porsche : Car
{
public Porsche(string brand, System.Drawing.Color color)
{
base.Brand = brand;
base.Color = color;
}
public Porsche(string brand)
{
base.Brand = brand;
}
public Porsche()
{
}
}
public class Mercedes : Car
{
public Mercedes(string brand, System.Drawing.Color color)
{
base.Brand = brand;
base.Color = color;
}
public Mercedes(string brand)
{
base.Brand = brand;
}
public Mercedes()
{
}
}
بسیار خوب. باز هم بهتر شد. آیا احساس می کنید که هنوز هم میشه این دو کلاس رو بهبود داد؟ لطفا به این کد دقت کنید:
public class Porsche : Car
{
public Porsche(string brand, System.Drawing.Color color)
: base(brand, color)
{
}
public Porsche(string brand)
: this(brand, System.Drawing.Color.Empty)
{
}
public Porsche()
{
}
}
public class Mercedes : Car
{
public Mercedes(string brand, System.Drawing.Color color)
: base(brand, color)
{
}
public Mercedes(string brand)
: this(brand, System.Drawing.Color.Empty)
{
}
public Mercedes()
{
}
}
تفاوت دو کد اخیر رو بررسی کنید. در کد آخر، دیگه عمل Assignment مستقیما انجام نمیشه، بلکه از طریق Constructor های دو کلاس این کار انجام میشه. همینطور به این مساله دقت کنید که چقدر هوشمندانه برنامه نویس با فراخوانی یک Constructor دیگه در همون کلاس، Constructor ای که تنها brand رو بعنوان پارامتر قبول میکنه رو پیاده سازی کرده. در نهایت، فراموش نکنید که کلاس Car رو abstract تعریف کنید، چون اصلا تمایلی نداریم کسی قادر به ساخت نمونه ای از کلاس Car باشه.
اکنون به Class Diagram این کد نگاه کنید و از اون لذت ببرید (سمت چپ قبل از انجام عمل Refactoring و سمت راست Class Diagram مربوطه پس از انجام عمل Refactoring را نمایش می دهد).