اصول طراحی SOLID در #C (قسمت چهارم)

Interface Segregation Principle
این چهارمین اصل از اصول SOLID است که به شرح زیر تعریف می شود.
کلاینت نباید مجبور به پیاده سازی رابطی شود که هرگز از آن استفاده نخواهد کرد.
این اصل بیان می کند که کد کلاینت نباید مجبور شود به متدهایی که استفاده نمی کند وابسته باشد. این اصل اجرای بسیاری از اینترفیسهای کوچک را به جای یک اینترفیس بزرگ ترویج میکند، زیرا به مشتریان اجازه میدهد اینترفیسهای مورد نیاز را انتخاب کرده و همان را پیادهسازی کنند.
توضیح
هدف از این اصل، تقسیم نرم افزار به کلاس های کوچکی است که اینترفیس یا متدهایی را که کلاس استفاده نمی کند، پیاده سازی نکند. این کار کمک می کند تا کلاس متمرکز، خالص و جدا از وابستگی ها باشد.
این اصل پیشنهاد میکند که یک اینترفیس بزرگ را پیادهسازی نکنید، در عوض باید تعداد زیادی اینترفیس کوچک وجود داشته باشند که میتوانند توسط کلاسهایی که نیاز به پیادهسازی آنها را دارند انتخاب شوند.
اینترفیسی که توسط کلاس پیاده سازی می شود باید با مسئولیت کلاس ارتباط نزدیک داشته باشد. اینترفیسها باید طبق اصل مسئولیت واحد در اصول SOLID طراحی شوند.
ما باید سعی کنیم اینترفیس های خود را کوچک نگه داریم زیرا اینترفیس های بزرگتر متدهای بیشتری را شامل می شوند و پیاده سازی ها ممکن است به متدهای زیادی نیاز نداشته باشند. اگر اینترفیسها را بزرگ نگه داریم، در نهایت با توابع زیادی در کلاس پیاده سازی کننده مواجه میشویم که ممکن است برخلاف اصل مسئولیت واحد باشد.
به کد زیر نگاهی بیندازید که در آن یک اینترفیس عمومی داریم که توسط بیش از یک کلاس پیاده سازی شده است.
public interface IUtility
{
bool LogData(string logdata);
string GetDbConnStringFromConfig();
bool SaveTransaction(object tranData);
object GetTransaction(string tranID);
}
بیایید اینترفیس فوق را در کلاس های مختلف مانند شکل زیر پیاده سازی کنیم.
public class ConfigParameters : IUtility
{
public string GetDbConnStringFromConfig()
{
string dbConn = string.Empty;
//Read Connection String From Config
return dbConn;
}
public object GetTransaction(string tranID)
{
throw new NotImplementedException();
}
public bool LogData(string logdata)
{
throw new NotImplementedException();
}
public bool SaveTransaction(object tranData)
{
throw new NotImplementedException();
}
}
public class Logger : IUtility
{
public bool LogData(string logdata)
{
//Log data to File
return true;
}
public string GetDbConnStringFromConfig()
{
throw new NotImplementedException();
}
public object GetTransaction(string tranID)
{
throw new NotImplementedException();
}
public bool SaveTransaction(object tranData)
{
throw new NotImplementedException();
}
}
public class TransactionOperations : IUtility
{
public object GetTransaction(string tranID)
{
Object objTran = new object();
//Retrieve Transaction
return objTran;
}
public bool SaveTransaction(object tranData)
{
//Save Transaction
return true;
}
public string GetDbConnStringFromConfig()
{
throw new NotImplementedException();
}
public bool LogData(string logdata)
{
throw new NotImplementedException();
}
}
اکنون که رابط IUtility
را در کلاس های مختلف پیاده سازی کرده ایم، هنگام پیادهسازی کلاسها، ما از Single Responsibility Principle در Solid Principles پیروی کردهایم، بنابراین میتوانیم ببینیم که در هیچ کلاسی، همه توابع را از اینترفیس پیادهسازی نکردهایم زیرا توابع در اینترفیس برای هیچ کلاسی مرتبط نیستند. به عنوان مثال، کلاس Logger فقط باید توابع مرتبط با گزارش را پیاده سازی کند و به طور مشابه، کلاس ConfigParameters فقط به تابع عملیات مربوط به پیکربندی نیاز دارد.
اجرای فوق اصل Interface Segregation را که بیان می کند کلاس ها نباید مجبور به پیاده سازی متدهایی شوند که هرگز از آنها استفاده نخواهند کرد نقض میکند. بنابراین بیایید پیاده سازی فوق را مطابق اصل جداسازی اینترفیس در اصول SOLID اصلاح کنیم.
همانطور که در زیر نشان داده شده است، یک اینترفیس به چندین اینترفیس کوچکتر تقسیم شده است.
public interface IConfigOperations
{
string GetDbConnStringFromConfig();
}
public interface ILogging
{
bool LogData(string logdata);
}
public interface ITransactionOperations
{
bool SaveTransaction(object tranData);
object GetTransaction(string tranID);
}
اکنون که اینترفیس ها را تعریف کردهایم، اجازه دهید این رابطها را در کلاسهایی که برای عملیات پیکربندی، ثبتنام و عملیات تراکنشها در اختیار داریم، پیادهسازی کنیم.
public class ConfigParameters : IConfigOperations
{
public string GetDbConnStringFromConfig()
{
string dbConn = string.Empty;
//Read Connection String From Config
return dbConn;
}
}
public class Logger : ILogging
{
public bool LogData(string logdata)
{
//Log data to File
return true;
}
}
public class TransactionOperations : ITransactionOperations
{
public object GetTransaction(string tranID)
{
Object objTran = new object();
//Retrieve Transaction
return objTran;
}
public bool SaveTransaction(object tranData)
{
//Save Transaction
return true;
}
}
همانطور که در کد بالا مشاهده می شود، با تجزیه یک اینترفیس بزرگ به چندین اینترفیس کوچکتر، توانستیم مسئولیت ها را از هم جدا کنیم و همچنین آنها را بین اینترفیس های مختلف تقسیم کنیم. این روش همچنین به ما اجازه میدهد تا با پیادهسازی اینترفیس های مرتبط با آن کلاس، کلاسها را بر روی مسئولیت واحد متمرکز کنیم.
فواید
- با پیاده سازی رابط های کوچکتر می توانیم مسئولیت ها را از هم جدا کنیم.
- کلاس ها می توانند از اینترفیس های مربوطه استفاده کنند و توابعی را که برای کلاس ها مورد نیاز است پیاده سازی کنند. بنابراین ما میتوانیم با حذف کدهایی که برای کلاس مفید نیستند، کلاس را تمیز نگه داریم.
سخن پایانی
این اصل استفاده از اینترفیس های کوچکتر را به جای یک اینترفیس بزرگ ترویج می کند. یک اینترفیس بزرگ ممکن است از نظر کدنویسی راحت باشد، اما ممکن است در یک اینترفیس بیش از یک مسئولیت داشته باشید که نگهداری آن دشوار می باشد. این اصل در Solid Principles به شما این امکان را می دهد که برنامه خود را به اجزای کوچکتر و قابل نگهداری تقسیم کنید.
دیدگاهتان را بنویسید