ویژگی (برنامه نویسی کامپیوتری)

در برنامه نویسی کامپیوتر ، یک **ویژگی** یک مفهوم زبانی است که مجموعه ای از روش ها را نشان می دهد که می تواند برای گسترش عملکرد یک کلاس استفاده شود.  

### منطق
در برنامه نویسی شی گرا، رفتار گاهی بین کلاس هایی که به یکدیگر مرتبط نیستند به اشتراک گذاشته می شود. برای مثال، بسیاری از کلاس‌های نامرتبط ممکن است متدهایی برای سریال‌سازی اشیا به JSON داشته باشند. از لحاظ تاریخی، چندین رویکرد برای حل این مشکل بدون تکرار کد در هر کلاسی که به رفتار نیاز دارد، وجود داشته است. روش‌های دیگر شامل وراثت چندگانه و میکس‌ها هستند، اما اینها دارای اشکالاتی هستند: اگر ترتیب اعمال میکس‌ها تغییر کند، یا اگر روش‌های جدیدی به کلاس‌های والد یا میکس‌ها اضافه شوند، ممکن است رفتار کد به‌طور غیرمنتظره‌ای تغییر کند.

ویژگی‌ها با اجازه دادن به کلاس‌ها برای استفاده از ویژگی و به دست آوردن رفتار مطلوب، این مشکلات را حل می‌کنند. اگر یک کلاس از بیش از یک ویژگی استفاده کند، ترتیب استفاده از ویژگی‌ها مهم نیست. متدهای ارائه شده توسط ویژگی‌ها دسترسی مستقیم به داده های کلاس دارند.

### خصوصیات
ویژگی‌ها جنبه های پروتکل ها (رابط ها) و میکس ها را ترکیب می کنند. مانند یک رابط، یک ویژگی یک یا چند امضای متد را تعریف می‌کند که کلاس‌های پیاده‌سازی باید پیاده‌سازی‌هایی را ارائه کنند. مانند یک mixin، یک ویژگی رفتار اضافی را برای کلاس پیاده‌سازی ارائه می‌کند.

در صورت تداخل نامگذاری بین متدهای ارائه شده توسط ویژگی‌ها مختلف، برنامه نویس باید صریحاً ابهام کند که کدام یک از آن متدها در کلاس استفاده می شود. بنابراین به صورت دستی *[[وراثت چندگانه|مشکل الماس]]* وراثت چندگانه را حل می کند. این با سایر روش‌های ترکیب‌بندی در برنامه‌نویسی شی‌گرا متفاوت است، جایی که نام‌های متضاد به طور خودکار با قوانین محدوده حل می‌شوند.

عملیاتی که با ویژگی‌ها قابل انجام است عبارتند از:  

* *مجموع متقارن* : عملیاتی که دو ویژگی مجزا را برای ایجاد یک ویژگی جدید ادغام می‌کند
* *override* (یا *مجموع نامتقارن* ): عملیاتی که با افزودن متدهایی به یک ویژگی موجود، و احتمالاً نادیده گرفتن برخی از روش‌های آن، یک ویژگی جدید را تشکیل می‌دهد.
* *نام مستعار* : عملیاتی که با افزودن یک نام جدید برای یک متد موجود، یک ویژگی جدید ایجاد می کند
* *exclusion* : عملیاتی که با حذف یک روش از یک ویژگی موجود، یک ویژگی جدید را تشکیل می دهد. (ترکیب این عملیات با نام مستعار یک عملیات *تغییر نام کم عمق را* به همراه دارد).

اگر روشی از یک ویژگی حذف شود، آن متد باید توسط کلاسی که آن ویژگی را مصرف می‌کند، یا توسط کلاس والد آن کلاس ارائه شود. این به این دلیل است که روش های ارائه شده توسط این ویژگی ممکن است روش حذف شده را صدا کنند.

ترکیب ویژگی جابجایی است (یعنی ویژگی‌ها داده شده *A* و *B* ، *A* + *B* معادل *B* + *A* است) و انجمنی (یعنی ویژگی‌ها داده شده *A* ، *B* ، و *C* ، ( *A*+ *B* ) + *C* معادل *A* + ( *B* + *C* ) است). 

### محدودیت‌ها
در حالی که ویژگی ها نسبت به بسیاری از گزینه ها مزایای قابل توجهی دارند، اما محدودیت های خاص خود را دارند.

#### روش های مورد نیاز
اگر یک ویژگی به طبقه مصرف کننده نیاز داشته باشد تا روش های خاصی را ارائه دهد، آن ویژگی نمی تواند بداند که آیا آن روش ها از نظر معنایی با نیازهای ویژگی معادل هستند یا خیر. برای برخی از زبان‌های پویا، مانند Perl، روش مورد نیاز فقط با نام متد قابل شناسایی است، نه با امضای کامل متد ، که تضمین مناسب بودن روش مورد نیاز را دشوارتر می‌کند.

#### مستثنی کردن متدها
اگر روشی از یک ویژگی حذف شود، آن روش به روشی «الزامی» برای آن ویژگی تبدیل می‌شود، زیرا روش‌های دیگر آن ویژگی ممکن است آن را نام ببرند.

### زبان های پشتیبانی شده
ویژگی ها در اصل از زبان برنامه نویسی Self  می آیند و توسط زبان های برنامه نویسی زیر پشتیبانی می شوند:

* **AmbientTalk**: ترکیبی از ویژگی‌های traits در Self (ارث‌بری چندگانه مبتنی بر شیء) و traits در Squeak (نیازمند ترکیب صریح traits توسط برنامه‌نویس) است. این زبان بر اساس پژوهش‌هایی دربارهٔ traits دارای وضعیت (stateful) و traits قابل انجماد (freezable) ساخته شده تا امکان تعریف وضعیت در درون traits فراهم شود، چیزی که در تعریف‌های اولیه ممکن نبود.
* **C#**: از نسخهٔ ۸.۰ به بعد، این زبان از «متدهای پیش‌فرض در واسط‌ها» (default interface methods) پشتیبانی می‌کند که برخی از ویژگی‌های traits را دارند.
* **++C**: در کتابخانهٔ استاندارد قالب (STL) و کتابخانهٔ استاندارد ++C برای پشتیبانی از کلاس‌های محفظهٔ عمومی و در کتابخانهٔ Boost TypeTraits استفاده می‌شود.
* **Curl**: کلاس‌های انتزاعی به‌عنوان mixin امکان پیاده‌سازی متدها را فراهم می‌کنند و بنابراین می‌توان آن‌ها را traits با نامی دیگر در نظر گرفت.
* **Fortress**: پشتیبانی دارد.
* **Groovy**: از نسخهٔ ۲.۳ به بعد پشتیبانی می‌شود.
* **Haskell**: در این زبان، traits با عنوان «کلاس‌های نوع» (type classes) شناخته می‌شوند.
* **Haxe**: از نسخهٔ ۲.۴.۰ به بعد، با عنوان «گسترش ایستا» (Static Extension) در مستندات شناخته می‌شود و از کلیدواژهٔ `using` استفاده می‌کند.
* **Java**: از نسخهٔ ۸ به بعد، از «متدهای پیش‌فرض» (default methods) در واسط‌ها پشتیبانی می‌کند که برخی ویژگی‌های traits را دارند.
* **JavaScript**: traits را می‌توان با استفاده از توابع و delegation پیاده‌سازی کرد یا از کتابخانه‌هایی استفاده کرد که traits را فراهم می‌کنند.
* **Julia**: چندین بسته برای پیاده‌سازی traits وجود دارند.
* **Kotlin**: از نسخهٔ M12 به بعد، traits با عنوان «واسط‌ها» (interfaces) شناخته می‌شوند.
* **Lasso**: پشتیبانی دارد.
* **Mojo**: از نسخهٔ ۰.۶.۰ به بعد پشتیبانی می‌شود.
* **OCaml**: traits را می‌توان با استفاده از امکانات مختلف زبان مانند ماژول‌ها، توابع سازنده (functor) و وراثت کلاس‌ها پیاده‌سازی کرد.
* **Perl**: با عنوان «نقش‌ها» (roles) شناخته می‌شوند و در کتابخانه‌هایی مانند Moose، Role::Tiny و Role::Basic پیاده‌سازی شده‌اند. در زبان خواهر Perl یعنی Raku نیز نقش دارند. همچنین با تصویب پیشنهاد OOP به نام Corinna، Perl پشتیبانی بومی از roles را خواهد داشت.
* **PHP**: از نسخهٔ ۵.۴ به بعد، PHP به کاربران اجازه می‌دهد تا از traits برای پیاده‌سازی چیزی شبیه به وراثت چندگانه استفاده کنند.
* **Python**: از طریق کتابخانه‌های شخص ثالث یا با استفاده از کلاس‌های mixin سطح بالاتر.
* **Racket**: traits را به‌صورت کتابخانه‌ای پشتیبانی می‌کند و از ماکروها، ساختارها و کلاس‌های مرتبه اول برای پیاده‌سازی آن‌ها بهره می‌گیرد.
* **Ruby**: با استفاده از ماژول‌های mixin می‌توان traits را پیاده‌سازی کرد.
* **Rust**: پشتیبانی بومی از traits دارد.
* **Scala**: با استفاده از کلیدواژهٔ `trait` از traits پشتیبانی می‌شود.

### مثال‌ها

#### سی‌شارپ
در سی شارپ 8.0 می توان پیاده سازی را به عنوان عضوی از یک رابط تعریف کرد.
```c#
using System;

namespace CSharp8NewFeatures;

interface ILogger
{
    // Traditional interface methods
    void Log(string message);
    void LogError(Exception exception);

    // Default interface method
    void LogWarning(string message)
    {
        Console.WriteLine(message);
    }        
}

class Logger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }

    public void LogError(Exception exception)
    {
        Console.WriteLine(exception.ToString());
    }
}

class Program
{
    static void Main(string[] args)
    {
        ILogger logger = new Logger();

        logger.LogWarning("Some warning message");
    }
}
```


#### PHP
این مثال از یک ویژگی برای تقویت کلاس های دیگر استفاده می کند:
```php
// The template
trait TSingleton
{
    private static $_instance = null;

    private function __construct() {} // Must have private default constructor and be aware not to open it in the class

    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }
}

class FrontController
{
    use TSingleton;
}

// Can also be used in already extended classes
class WebSite extends SomeClass
{
    use TSingleton;
}
```
این امکان شبیه سازی جنبه های وراثت چندگانه را فراهم می کند:
```php
trait TBounding
{
    public $x, $y, $width, $height;
}

trait TMoveable
{
    public function moveTo($x, $y)
    {
        // …
    }
}

trait TResizeable
{
    public function resize($newWidth, $newHeight)
    {
        // …
    }
}

class Rectangle
{
    use TBounding, TMoveable, TResizeable;

    public function fillColor($color)
    {
        // …
    }
}
```


#### Rust
یک ویژگی در Rust مجموعه‌ای از روش‌ها را اعلام می‌کند که یک نوع باید پیاده‌سازی کند.  کامپایلرهای Rust نیازمند توضیح ویژگی‌ها هستند که ایمنی ژنریک ها را در Rust تضمین می کند.
```rust
// type T must have the "Ord" trait
// so that ">" and "<" operations can be done
fn max<T: Ord>(a: &[T]) -> Option<&T> {
    let mut result = a.first()?;
    for n in a {
        if *n > *result {
            result = &n;
        }
    }
    Some(result)
}
```
برای ساده‌سازی اجرای خسته‌کننده و مکرر ویژگی‌هایی مانند `Debug` و `Ord` ، می‌توان از ماکرو `derive` برای درخواست از کامپایلرها برای تولید خودکار پیاده‌سازی‌های خاص استفاده کرد.  ویژگی‌ها قابل مشتق عبارتند از: `Clone` ، `Copy` ، `Debug` ، `Default` ، `PartialEq` ، `Eq` ، `PartialOrd` ، `Ord` و `Hash` .

### همچنین ببینید

* روش گسترش
* رابط (برنامه نویسی شی گرا)
* پلی مورفیسم پارامتریک
* UFCS

### مراجع