نحوه استفاده از کلاس های abstract در سی شارپ

از کلاس های abstract (انتزاعی) زمانی استفاده می شود که قصد داشته باشید متدها و propertyهایی را صرفا جهت ارث بری تعریف نمایید. از کلاسهای abstract تنها برای ارث بری می توان استفاده نمود و اگر اقدام به ساخت یک نمونه از آنها کنید با خطا مواجه خواهید شد.

نحوه استفاده

قصد داریم یک برنامه برای محاسبه مساحت اشکال هندسی ایجاد نماییم. یکی از روش های حل این مسأله ساخت یک کلاس abstract به نام Shape می باشد که می بایست درون آن متدی برای محاسبه مساحت اضافه شود. برای ساخت کلاس های abstract، قبل از نام کلاس از کلمه کلیدی abstract استفاده می شود.

abstract class Shape
{
    abstract public int Area();
}

نکته: کلاس های abstract حتما باید متدی از نوع abstract داشته باشند.

پس از تعریف کلاس پایه از نوع abstract می توانید کلاسی به نام Square داشته باشید که از این کلاس ارث بری داشته باشد:

class Square : Shape
{
    int side = 0;
    public Square(int number)
    {
        side = number;
    }
    public override int Area()
    {
        return side * side;
    }
}

توجه داشته باشید که هنگام پیاده سازی متدهای کلاس پایه، حتما باید آنها را override نمایید. پس از تکمیل کلاس Shape می توان از آن در متد Main استفاده نمود.

class Program
{
    static void Main(string[] args)
    {
        Square square = new Square(4);
        Console.WriteLine("The Area is:" + square.Area());
        Console.ReadLine();
    }
}

مقایسه کلاس های abstract و interface

استفاده از کلاس های abstract شباهت زیادی به interfaceها دارد اما تفاوت ها عمده ای بین آنها وجود دارد.

مزایای abstract نسبت به interface

  1. در interface فقط می توان متد تعریف نمود اما در abstract می توان علاوه بر متد، property, indexer و ... نیز داشت.
  2. در interface کدهایی درون متدها نوشته نمی شود اما در abstract، متدها می توانند حاوی کد باشند.
  3. کلاسهای abstract می توانند حاوی اعضای static باشند، در حالیکه interfaceها این قابلیت را ندارند.
  4. abstractها برخلاف interfaceها می توانند حاوی متد سازنده (constructor) باشد.
  5. کلاسهای abstract دارای performance بالاتری نسبت به interfaceها می باشند.

مهمترین مزیت interface نسبت به abstract، قابلیت ارث بری چندگانه از interfaceها می باشد در حالیکه تنها از یک کلاس abstract می توان ارث بری داشت!

مثال: قصد داریم با استفاده از مفاهیم آموزش داده شده، کلاس های مورد نیاز برای یک فروشگاه را تعریف نماییم.

تحلیل: برخی از ویژگی ها بین تمام محصولات مشترک بوده و برخی دیگر ممکن است منحصر به یک محصول خاص باشد. بنابراین ابتدا کلاسی برای محصول تعریف می نماییم که حاوی ویژگی های مشترک باشد، از آنجا که قصد داریم از این کلاس فقط برای ارث بری استفاده نماییم می بایست بصورت abstract تعریف گردد.

abstract class Product
{
    public string Brand { get; set; }
    public string Model { get; set; }
    public int Price { get; set; }
    public Product(string brand, string model, int price)
    {
        Brand = brand;
        Model = model;
        Price = price;
    }
}

نکته: در صورتیکه قصد نداشته باشید محدودیتی روی فیلدها اعمال نمایید، همانند مثال فوق می توانید مستقیما property تعریف نموده و از آن استفاده نمایید.

همه کلاس هایی که از Product ارث بری خواهند داشت، می بایست متدی برای نمایش اطلاعات داشته باشند بنابراین در کلاس Product یک متد abstract نیز اضافه می کنیم.

abstract class Product
{
    public string Brand { get; set; }
    public string Model { get; set; }
    public int Price { get; set; }
    public Product(string brand, string model, int price)
    {
        Brand = brand;
        Model = model;
        Price = price;
    }
    abstract public void ShowInfo();
}

هر محصول می تواند دارای تخفیف باشد اما این تخفیف برای همه محصولات به یک شکل مورد استفاده قرار می گیرد، بنابراین می توان متد AddDiscount را همانند یک متد عادی به کلاس Product اضافه نمود.

abstract class Product
{
    public string Brand { get; set; }
    public string Model { get; set; }
    public int Price { get; set; }
    public Product(string brand, string model, int price)
    {
        Brand = brand;
        Model = model;
        Price = price;
    }
    
    abstract public void ShowInfo();
    public void AddDiscount(int amount)
    {
        Price = Price - (Price * amount / 100);
    }
}

از آنجا که این متد بصورت عادی تعریف شده و وظیفه آن اعمال تخفیف می باشد بنابراین نیازی به پیاده سازی در کلاس های مشتق شده نخواهد داشت.

حال می توانید کلاسی به نام Monitor به پروژه اضافه کنید که از Product ارث بری داشته باشد. این کلاس علاوه بر propertyهای فوق، یک property دیگر به نام Resolution خواهد داشت که مختص خود می باشد.

class Monitor:Product
{
    public string Resolution { get; set; }
}

حال در متد سازنده این کلاس، می بایست مقادیر مورد نیاز را دریافت کنیم.

public Monitor(string brand,string model, string resolution, int price)
{
    Resolution = resolution;
}

توجه داشته باشید که سه فیلد اول دریافت شده در متد سازنده کلاس Monitor باید به متد سازنده Product ارسال شوند که این امر با ارث بری متد سازنده از base امکان پذیر است.

public Monitor(string brand,string model, string resolution, int price):base(brand,model,price)
{
    Resolution = resolution;
}

حال باید متد ShowInfo در کلاس Monitor پیاده سازی شود.

public override void ShowInfo()
{
    Console.WriteLine("Monitor Info: " + Brand +", " + Model + ", " + Resolution + ", " + Price);
}

کدهای کامل کلاس Monitor به شکل زیر خواهد بود.

class Monitor : Product
{
    public string Resolution { get; set; }

    public Monitor(string brand, string model, string resolution, int price) : base(brand, model, price)
    {
        Resolution = resolution;
    }
    public override void ShowInfo()
    {
        Console.WriteLine("Monitor Info: " + Brand + ", " + Model + ", " + Resolution + ", " + Price);
    }
}

پس از تکمیل این دو کلاس، می توان از کلاس Monitor در برنامه استفاده نمود.

class Program
{
    static void Main(string[] args)
    {
        Monitor dell = new Monitor("Dell", "SE2219H", "Full HD", 1350);
        dell.ShowInfo();
        dell.AddDiscount(15);
        dell.ShowInfo();
        Console.ReadLine();
    }
}

همانطور که مشاهده می کنید متد AddDiscount چون بصورت abstract تعریف نشده بود، نیازی به پیاده سازی در کلاس Monitor نداشت اما توسط object ساخته شده از Monitor قابل استفاه می باشد. خروجی این برنامه به شکل زیر خواهد بود.

نحوه استفاده از کلاس های abstract در سی شارپ