اصول جامد در Dart (Flutter) – انجمن DEV

اصول SOLID مجموعهای از اصول برای توسعه نرمافزار است که هدف آن حفظ، مقیاسپذیری و انعطافپذیری بیشتر نرمافزار است. در این مقاله نحوه اعمال اصول SOLID در فلاتر را با مثال های کد مورد بحث قرار می دهیم.
S – اصل مسئولیت واحد (SRP)
اصل مسئولیت واحد (SRP) بیان می کند که یک کلاس باید تنها یک دلیل برای تغییر داشته باشد. به عبارت دیگر، یک کلاس باید تنها یک مسئولیت داشته باشد. نگهداری و اصلاح کلاسی که چندین مسئولیت دارد سخت است.
در اینجا نمونه ای از کلاسی است که SRP را نقض می کند:
class User {
int id;
String name;
void save() {
// save user to database
}
void sendEmail() {
// send email to user
}
}
این کلاس SRP را نقض می کند زیرا دو وظیفه دارد: ذخیره کاربر در پایگاه داده و ارسال ایمیل به کاربر. یک روش بهتر تقسیم کلاس به دو کلاس جداگانه است:
class User {
int id;
String name;
}
class UserRepository {
void save(User user) {
// save user to database
}
}
class EmailService {
void sendEmail(User user) {
// send email to user
}
}
O – اصل باز/بسته (OCP)
اصل باز/بسته (OCP) بیان می کند که یک کلاس باید برای توسعه باز باشد اما برای اصلاح بسته شود. به عبارت دیگر، شما باید بتوانید رفتار یک کلاس را بدون تغییر کد منبع آن گسترش دهید.
در اینجا نمونه ای از کلاسی است که OCP را نقض می کند:
class Rectangle {
double width;
double height;
double area() {
return width * height;
}
}
اگر بخواهیم یک کلاس جدید برای محاسبه مساحت یک دایره ایجاد کنیم، باید آن را تغییر دهیم Rectangle
کلاسی که در حال حاضر OCP را نقض می کند. یک رویکرد بهتر این است که یک رابط برای محاسبه مساحت ایجاد کنید و هر شکلی رابط را پیاده سازی کند:
abstract class Shape {
double area();
}
class Rectangle implements Shape {
double width;
double height;
double area() {
return width * height;
}
}
class Circle implements Shape {
double radius;
double area() {
return pi * pow(radius, 2);
}
}
L – اصل جایگزینی لیسکوف (LSP)
اصل جایگزینی لیسکوف (LSP) بیان می کند که اشیاء یک سوپرکلاس باید بتوانند با اشیاء یک زیر کلاس جایگزین شوند بدون اینکه بر صحت برنامه تأثیر بگذارند. به عبارت دیگر، یک زیر کلاس باید بتواند بدون شکستن کد، سوپرکلاس خود را جایگزین کند.
در اینجا نمونه ای از کلاسی است که LSP را نقض می کند:
class Rectangle {
double width;
double height;
double area() {
return width * height;
}
}
class Square extends Rectangle {
double side;
@override
double set width(double value) => side = value;
@override
double set height(double value) => side = value;
}
این کلاس LSP را نقض می کند زیرا a Square
نمی توان به جای a استفاده کرد Rectangle
بدون اینکه بر صحت برنامه تأثیر بگذارد. یک رویکرد بهتر ایجاد یک کلاس جداگانه برای Square
:
abstract class Shape {
double area();
}
class Rectangle implements Shape {
double width;
double height;
double area() {
return width * height;
}
}
class Square implements Shape {
double side;
double area() {
return pow(side, 2);
}
}
I – اصل جداسازی رابط (ISP)
اصل جداسازی رابط (ISP) بیان میکند که یک کلاس نباید مجبور به پیادهسازی رابطهایی شود که از آنها استفاده نمیکند. به عبارت دیگر، یک کلاس فقط باید به واسط هایی که نیاز دارد بستگی داشته باشد.
در اینجا نمونه ای از کلاسی است که ISP را نقض می کند:
abstract class Shape {
double area();
double perimeter();
}
class Rectangle implements Shape {
double width;
double height;
double area() {
return width * height;
}
double perimeter() {
return 2 * (width + height);
}
}
class Circle implements Shape {
double radius;
double area() {
return pi * pow(radius, 2);
}
double perimeter() {
return 2 * pi * radius;
}
}
این کلاس ISP را نقض می کند زیرا a Circle
محیطی ندارد یک رویکرد بهتر ایجاد رابط های جداگانه برای مساحت و محیط است:
abstract class Area {
double area();
}
abstract class Perimeter {
double perimeter();
}
class Rectangle implements Area, Perimeter {
double width;
double height;
double area() {
return width * height;
}
double perimeter() {
return 2 * (width + height);
}
}
class Circle implements Areaand {
double radius;
double area() {
return pi * pow(radius, 2);
}
}
د – اصل وارونگی وابستگی (DIP)
اصل وارونگی وابستگی (DIP) بیان می کند که ماژول های سطح بالا نباید به ماژول های سطح پایین وابسته باشند. هر دو باید به انتزاعات بستگی داشته باشند. به عبارت دیگر، شما باید به انتزاعات وابسته باشید، نه به پیاده سازی های عینی.
در اینجا نمونه ای از کلاسی است که DIP را نقض می کند:
class UserRepository {
void save(User user) {
// save user to database
}
}
class UserService {
UserRepository userRepository;
UserService(this.userRepository);
void saveUser(User user) {
userRepository.save(user);
}
}
این کلاس DIP را نقض می کند زیرا UserService
بستگی به اجرای ملموس دارد UserRepository
. یک رویکرد بهتر این است که به یک انتزاع وابسته باشیم:
abstract class UserRepository {
void save(User user);
}
class FirebaseUserRepository implements UserRepository {
void save(User user) {
// save user to Firebase
}
}
class UserService {
UserRepository userRepository;
UserService(this.userRepository);
void saveUser(User user) {
userRepository.save(user);
}
}
با توجه به یک انتزاع، UserService
دیگر به اجرای خاصی از UserRepository
، آن را انعطاف پذیرتر و قابل نگهداری تر می کند.
نتیجه
اصول SOLID برای ساختن نرم افزار قابل نگهداری، مقیاس پذیر و انعطاف پذیر مهم هستند. با پیروی از این اصول در کد فلاتر خود، می توانید کدی ایجاد کنید که نگهداری و اصلاح آن آسان تر باشد. به یاد داشته باشید، اصول SOLID قوانینی نیستند، بلکه دستورالعمل هایی هستند که می توانند به شما در نوشتن کد بهتر کمک کنند.