برنامه نویسی

معماری کد پاک و BLoC در فلاتر: راهنمای جامع برای مبتدیان و متخصصان

Summarize this content to 400 words in Persian Lang
Flutter روشی را که ما در ساخت اپلیکیشن های موبایل و وب چند پلتفرمی ایجاد می کنیم متحول کرده است. با این حال، با افزایش پیچیدگی پروژه شما، به یک رویکرد ساختاریافته برای حفظ مقیاس پذیری، خوانایی و آزمایش پذیری نیاز دارید. اینجاست که معماری کد پاک و BLoC (جزء منطق تجاری) الگو وارد بازی می شود این مقاله شما را از طریق مفاهیم اساسی و پیشرفته این دو الگوی معماری کلیدی راهنمایی می‌کند و به توسعه‌دهندگان مبتدی و با تجربه کمک می‌کند تا نحوه استفاده از آنها را در فلاتر درک کنند.

فهرست مطالب

معماری کد پاک چیست؟
چرا از معماری کد پاک در فلاتر استفاده کنیم؟
لایه های معماری کد پاک
مقدمه ای بر الگوی BLoC
چرا BLoC با معماری پاک؟

ساخت اپلیکیشن Flutter با استفاده از Clean Architecture و BLoC

ساختار پروژه
پیاده سازی لایه دامنه
پیاده سازی لایه داده
پیاده سازی لایه ارائه (BLoC)

نمونه کد کامل
تست معماری
بهترین روش ها و نکات پیشرفته

1. معماری کد پاک چیست؟

معماری کد پاک یک الگوی طراحی نرم افزار است که توسط رابرت سی مارتین (همچنین به عنوان عمو باب شناخته می شود). هدف اصلی Clean Code Architecture این است که اطمینان حاصل شود جداسازی نگرانی ها. این سیستم را به تقسیم می کند لایه ها، هر کدام مسئولیت مشخصی دارند. این لایه ها عبارتند از:

لایه ارائه (UI)

لایه دامنه (منطق کسب و کار)

لایه داده (منابع داده ها)

معماری این را تضمین می کند منطق کسب و کار از وابستگی های خارجی جدا شده است مانند چارچوب‌های رابط کاربری، پایگاه‌های داده یا کتابخانه‌های شبکه، کد شما را می‌سازند انعطاف پذیرتر، قابل استفاده مجدد و آزمایش پذیرتر.

اصول کلیدی معماری پاک

تفکیک نگرانی ها: بخش‌های مختلف کد باید مسئولیت‌های متفاوتی را انجام دهند.

استقلال: منطق اصلی کسب و کار باید مستقل از UI، منابع داده یا هر چارچوب خارجی باشد.

آزمایش پذیری: از آنجایی که منطق کسب و کار شما از عناصر خارجی جدا شده است، نوشتن تست های واحد برای آن آسان تر است.

2. چرا از معماری کد پاک در فلاتر استفاده کنیم؟

در حالی که Flutter امکان توسعه سریع رابط کاربری را فراهم می کند، معماری پاک به شما کمک می کند پیچیدگی را در برنامه های بزرگتر مدیریت کنید. در اینجا چند دلیل برای استفاده از Clean Code Architecture در Flutter آورده شده است:

قابلیت نگهداری: تفکیک نگرانی‌ها تضمین می‌کند که تغییرات در یک لایه روی لایه‌های دیگر تأثیر نمی‌گذارد.

مقیاس پذیری: همانطور که برنامه شما رشد می کند، Clean Architecture گسترش قابلیت ها را بدون تغییر مجدد بخش های بزرگی از پایگاه کد آسان تر می کند.

آزمایش پذیری: با جداسازی منطق کسب و کار، می توانید بدون وابستگی به رابط کاربری یا منابع داده، تست های واحد معنی دار بنویسید.

3. لایه های معماری کد پاک

در Clean Code Architecture، سه لایه اصلی وجود دارد:

1. لایه دامنه (هسته)

این است قلب برنامه شما. شامل:

نهادها: کلاس های دارت ساده که مدل های تجاری را نشان می دهند.

موارد استفاده: تعامل هایی که منطق و قوانین تجاری را در بر می گیرند.

مخازن: قراردادهای انتزاعی که نحوه واکشی داده ها را مشخص می کند.

// entities/user_entity.dart
class UserEntity {
final String id;
final String name;

UserEntity({required this.id, required this.name});
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

// usecases/get_user_usecase.dart
class GetUserUseCase {
final UserRepository repository;

GetUserUseCase(this.repository);

FutureUserEntity> execute(String userId) {
return repository.getUser(userId);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

2. لایه داده

این لایه منابع داده را مدیریت می کند و رابط های مخزن تعریف شده در لایه دامنه را پیاده سازی می کند. شامل:

مدل های داده: کلاس هایی که نشان دهنده داده های واکشی شده از API ها یا پایگاه های داده محلی هستند.

منابع داده: پیاده سازی برای درخواست های شبکه، پایگاه های داده محلی و غیره.

پیاده سازی مخزن: پیاده سازی های عینی مخزن.

// data/models/user_model.dart
class UserModel {
final String id;
final String name;

UserModel({required this.id, required this.name});

factory UserModel.fromJson(MapString, dynamic> json) {
return UserModel(
id: json[‘id’],
name: json[‘name’],
);
}

MapString, dynamic> toJson() {
return {
‘id’: id,
‘name’: name,
};
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

// data/repositories/user_repository_impl.dart
class UserRepositoryImpl implements UserRepository {
final RemoteDataSource remoteDataSource;

UserRepositoryImpl(this.remoteDataSource);

@override
FutureUserEntity> getUser(String userId) async {
final userModel = await remoteDataSource.fetchUser(userId);
return UserEntity(id: userModel.id, name: userModel.name);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

3. لایه ارائه

این لایه شامل UI و مدیریت دولتی منطق اینجاست که الگوی BLoC ما از BLoC برای مدیریت وضعیت و تعامل با موارد استفاده لایه دامنه استفاده می کنیم.

// presentation/bloc/user_bloc.dart
class UserBloc extends BlocUserEvent, UserState> {
final GetUserUseCase getUserUseCase;

UserBloc(this.getUserUseCase) : super(UserInitial());

@override
StreamUserState> mapEventToState(UserEvent event) async* {
if (event is GetUserEvent) {
yield UserLoading();
try {
final user = await getUserUseCase.execute(event.userId);
yield UserLoaded(user);
} catch (e) {
yield UserError(“Couldn’t fetch user”);
}
}
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

4. مقدمه ای بر الگوی BLoC

BLoC (جزء منطق تجاری) یک الگوی مدیریت حالت است که جدا کردن منطق ارائه را از منطق تجاری در یک برنامه فلاتر آسان می کند. اجزای اصلی الگوی BLoC عبارتند از:

رویدادها: اقداماتی که کاربر یا سیستم راه اندازی می کند.

ایالات: وضعیت رابط کاربری بر اساس رویدادها.

BLoC: منطق تجاری را با نگاشت رویدادها به ایالت ها مدیریت می کند.

مزیت اصلی BLoC این است که به ما اجازه می دهد رابط کاربری را از منطق جدا کنیم. BLoC به رویدادها گوش می دهد (مانند فشار دادن دکمه ها) و حالت های جدیدی را منتشر می کند که UI می تواند به آنها گوش دهد.

// Event
abstract class UserEvent {}

class GetUserEvent extends UserEvent {
final String userId;

GetUserEvent(this.userId);
}

// State
abstract class UserState {}

class UserInitial extends UserState {}

class UserLoading extends UserState {}

class UserLoaded extends UserState {
final UserEntity user;

UserLoaded(this.user);
}

class UserError extends UserState {
final String message;

UserError(this.message);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

5. چرا BLoC با معماری پاک؟

استفاده از BLoC با معماری پاک تضمین می‌کند جدایی واضح بین UI و منطق تجاری، تست و نگهداری کد را آسان می کند. BLoC مسئول مدیریت انتقال‌های حالت و قوانین تجاری است، در حالی که لایه‌های معماری پاک تضمین می‌کنند که BLoC فقط با بخش‌های ضروری پایگاه کد، مانند موارد استفاده و مخازن، تعامل دارد.

6. ساختن یک اپلیکیشن فلاتر با استفاده از Clean Architecture و BLoC

اکنون، بیایید یک برنامه Flutter با استفاده از Clean Architecture و BLoC بسازیم. ما یک برنامه ساده ایجاد خواهیم کرد که داده های کاربر را از یک API واکشی می کند و آن را روی صفحه نمایش می دهد.

ساختار پروژه

lib/
├── data/
│ ├── models/
│ ├── repositories/
│ └── datasources/
├── domain/
│ ├── entities/
│ └── usecases/
├── presentation/
│ ├── bloc/
│ └── screens/
└── main.dart

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی لایه دامنه

ابتدا آن را تعریف کنید UserEntity و UserRepository.

// domain/entities/user_entity.dart
class UserEntity {
final String id;
final String name;

UserEntity({required this.id, required this.name});
}

// domain/repositories/user_repository.dart
abstract class UserRepository {
FutureUserEntity> getUser(String userId);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بعد، ایجاد کنید GetUserUseCase برای محصور کردن منطق کسب و کار

// domain/usecases/get_user_usecase.dart
class GetUserUseCase {
final UserRepository repository;

GetUserUseCase(this.repository);

FutureUserEntity> execute(String userId) {
return repository.getUser(userId);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی لایه داده

را تعریف کنید UserModel و مخزن را پیاده سازی کنید.

// data/models/user_model.dart
class UserModel {
final String id;
final String name;

UserModel({required this.id, required this.name});

factory UserModel.fromJson(MapString, dynamic> json) {
return UserModel(
id: json[‘id’],
name: json[‘name’],
);
}
}

// data/repositories/user_repository_impl.dart
class UserRepositoryImpl implements UserRepository {
final RemoteDataSource remoteDataSource;

UserRepositoryImpl(this.remoteDataSource);

@override
FutureUserEntity> getUser(String userId) async {
final userModel = await remoteDataSource.fetchUser(userId);
return UserEntity(id: userModel.id, name: userModel.name);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را اجرا کنید RemoteDataSource برای درخواست های شبکه

// data/datasources/remote_data_source.dart
class RemoteDataSource {
FutureUserModel> fetchUser(String userId

) async {
// Fake network request for simplicity
await Future.delayed(Duration(seconds: 2));
return UserModel(id: userId, name: ‘John Doe’);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی لایه ارائه (BLoC)

ایجاد کنید UserBloc برای مدیریت دولتی

// presentation/bloc/user_bloc.dart
class UserBloc extends BlocUserEvent, UserState> {
final GetUserUseCase getUserUseCase;

UserBloc(this.getUserUseCase) : super(UserInitial());

@override
StreamUserState> mapEventToState(UserEvent event) async* {
if (event is GetUserEvent) {
yield UserLoading();
try {
final user = await getUserUseCase.execute(event.userId);
yield UserLoaded(user);
} catch (e) {
yield UserError(“Couldn’t fetch user”);
}
}
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی UI

اکنون، UI را با استفاده از آن پیاده سازی کنید BlocBuilder برای گوش دادن به تغییرات حالت

// presentation/screens/user_screen.dart
class UserScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(‘User Profile’)),
body: BlocProvider(
create: (context) => UserBloc(GetUserUseCase(UserRepositoryImpl(RemoteDataSource()))),
child: UserProfile(),
),
);
}
}

class UserProfile extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilderUserBloc, UserState>(
builder: (context, state) {
if (state is UserInitial) {
return Center(child: Text(‘Press the button to fetch user data.’));
} else if (state is UserLoading) {
return Center(child: CircularProgressIndicator());
} else if (state is UserLoaded) {
return Center(child: Text(‘User: ${state.user.name}’));
} else if (state is UserError) {
return Center(child: Text(state.message));
}
return Container();
},
);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

7. نمونه کد کامل

در اینجا کد کامل این برنامه با Clean Architecture و BLoC در Flutter آمده است:

اصلی.دارت

void main() {
runApp(MaterialApp(
home: UserScreen(),
));
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

8. تست معماری

یکی از مزایای معماری پاک این است آزمون پذیری. بیایید تست های واحد بنویسیم GetUserUseCase اطمینان حاصل شود که منطق کسب و کار همانطور که انتظار می رود کار می کند.

void main() {
final mockUserRepository = MockUserRepository();
final getUserUseCase = GetUserUseCase(mockUserRepository);

test(‘should return user when called with a valid ID’, () async {
// Arrange
final user = UserEntity(id: ‘1’, name: ‘John Doe’);
when(mockUserRepository.getUser(any)).thenAnswer((_) async => user);

// Act
final result = await getUserUseCase.execute(‘1’);

// Assert
expect(result, user);
});
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

9. بهترین روش ها و نکات پیشرفته

از تزریق وابستگی استفاده کنید: استفاده از بسته ای مانند را در نظر بگیرید get_it برای مدیریت وابستگی ها به روشی مقیاس پذیر.

از کوپلینگ محکم خودداری کنید: همیشه اطمینان حاصل کنید که منطق کسب و کار شما به چارچوب های خارجی مانند Flutter، API ها یا پایگاه داده ها بستگی ندارد.

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

نتیجه گیری

Clean Code Architecture و الگوی BLoC ابزارهای قدرتمندی هستند که به ساختار برنامه‌های Flutter شما کمک می‌کنند و اطمینان می‌دهند که مقیاس‌پذیر، قابل نگهداری و آزمایش‌پذیر هستند. با اجرای اصول مورد بحث در اینجا، هم مبتدیان و هم توسعه دهندگان با تجربه می توانند برنامه های کاربردی با ساختار و کیفیت بالا ایجاد کنند.

زیبایی واقعی این رویکرد در آن نهفته است انعطاف پذیری و مدولار بودن. رابط کاربری شما از منطق کسب و کار جدا شده است، و منطق کسب و کار از منابع داده جدا شده است، که گسترش یا بازسازی بخش هایی از برنامه شما را با رشد آن بسیار آسان تر می کند.

به راحتی می توانید مفاهیم معرفی شده در این مقاله را تغییر دهید و بر اساس آن کار کنید. چه در حال ساخت یک برنامه کوچک یا یک برنامه بزرگ در سطح سازمانی باشید، استفاده از Clean Architecture و BLoC شما را در مسیر نوشتن قرار می دهد. قابل نگهداری و مقیاس پذیر کد

Flutter روشی را که ما در ساخت اپلیکیشن های موبایل و وب چند پلتفرمی ایجاد می کنیم متحول کرده است. با این حال، با افزایش پیچیدگی پروژه شما، به یک رویکرد ساختاریافته برای حفظ مقیاس پذیری، خوانایی و آزمایش پذیری نیاز دارید. اینجاست که معماری کد پاک و BLoC (جزء منطق تجاری) الگو وارد بازی می شود این مقاله شما را از طریق مفاهیم اساسی و پیشرفته این دو الگوی معماری کلیدی راهنمایی می‌کند و به توسعه‌دهندگان مبتدی و با تجربه کمک می‌کند تا نحوه استفاده از آنها را در فلاتر درک کنند.

فهرست مطالب

  1. معماری کد پاک چیست؟
  2. چرا از معماری کد پاک در فلاتر استفاده کنیم؟
  3. لایه های معماری کد پاک
  4. مقدمه ای بر الگوی BLoC
  5. چرا BLoC با معماری پاک؟
  6. ساخت اپلیکیشن Flutter با استفاده از Clean Architecture و BLoC

    • ساختار پروژه
    • پیاده سازی لایه دامنه
    • پیاده سازی لایه داده
    • پیاده سازی لایه ارائه (BLoC)
  7. نمونه کد کامل
  8. تست معماری
  9. بهترین روش ها و نکات پیشرفته

1. معماری کد پاک چیست؟

معماری کد پاک یک الگوی طراحی نرم افزار است که توسط رابرت سی مارتین (همچنین به عنوان عمو باب شناخته می شود). هدف اصلی Clean Code Architecture این است که اطمینان حاصل شود جداسازی نگرانی ها. این سیستم را به تقسیم می کند لایه ها، هر کدام مسئولیت مشخصی دارند. این لایه ها عبارتند از:

  • لایه ارائه (UI)
  • لایه دامنه (منطق کسب و کار)
  • لایه داده (منابع داده ها)

معماری این را تضمین می کند منطق کسب و کار از وابستگی های خارجی جدا شده است مانند چارچوب‌های رابط کاربری، پایگاه‌های داده یا کتابخانه‌های شبکه، کد شما را می‌سازند انعطاف پذیرتر، قابل استفاده مجدد و آزمایش پذیرتر.

اصول کلیدی معماری پاک

  • تفکیک نگرانی ها: بخش‌های مختلف کد باید مسئولیت‌های متفاوتی را انجام دهند.
  • استقلال: منطق اصلی کسب و کار باید مستقل از UI، منابع داده یا هر چارچوب خارجی باشد.
  • آزمایش پذیری: از آنجایی که منطق کسب و کار شما از عناصر خارجی جدا شده است، نوشتن تست های واحد برای آن آسان تر است.

2. چرا از معماری کد پاک در فلاتر استفاده کنیم؟

در حالی که Flutter امکان توسعه سریع رابط کاربری را فراهم می کند، معماری پاک به شما کمک می کند پیچیدگی را در برنامه های بزرگتر مدیریت کنید. در اینجا چند دلیل برای استفاده از Clean Code Architecture در Flutter آورده شده است:

  • قابلیت نگهداری: تفکیک نگرانی‌ها تضمین می‌کند که تغییرات در یک لایه روی لایه‌های دیگر تأثیر نمی‌گذارد.
  • مقیاس پذیری: همانطور که برنامه شما رشد می کند، Clean Architecture گسترش قابلیت ها را بدون تغییر مجدد بخش های بزرگی از پایگاه کد آسان تر می کند.
  • آزمایش پذیری: با جداسازی منطق کسب و کار، می توانید بدون وابستگی به رابط کاربری یا منابع داده، تست های واحد معنی دار بنویسید.

3. لایه های معماری کد پاک

در Clean Code Architecture، سه لایه اصلی وجود دارد:

1. لایه دامنه (هسته)

این است قلب برنامه شما. شامل:

  • نهادها: کلاس های دارت ساده که مدل های تجاری را نشان می دهند.
  • موارد استفاده: تعامل هایی که منطق و قوانین تجاری را در بر می گیرند.
  • مخازن: قراردادهای انتزاعی که نحوه واکشی داده ها را مشخص می کند.
// entities/user_entity.dart
class UserEntity {
  final String id;
  final String name;

  UserEntity({required this.id, required this.name});
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

// usecases/get_user_usecase.dart
class GetUserUseCase {
  final UserRepository repository;

  GetUserUseCase(this.repository);

  FutureUserEntity> execute(String userId) {
    return repository.getUser(userId);
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

2. لایه داده

این لایه منابع داده را مدیریت می کند و رابط های مخزن تعریف شده در لایه دامنه را پیاده سازی می کند. شامل:

  • مدل های داده: کلاس هایی که نشان دهنده داده های واکشی شده از API ها یا پایگاه های داده محلی هستند.
  • منابع داده: پیاده سازی برای درخواست های شبکه، پایگاه های داده محلی و غیره.
  • پیاده سازی مخزن: پیاده سازی های عینی مخزن.
// data/models/user_model.dart
class UserModel {
  final String id;
  final String name;

  UserModel({required this.id, required this.name});

  factory UserModel.fromJson(MapString, dynamic> json) {
    return UserModel(
      id: json['id'],
      name: json['name'],
    );
  }

  MapString, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
    };
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

// data/repositories/user_repository_impl.dart
class UserRepositoryImpl implements UserRepository {
  final RemoteDataSource remoteDataSource;

  UserRepositoryImpl(this.remoteDataSource);

  @override
  FutureUserEntity> getUser(String userId) async {
    final userModel = await remoteDataSource.fetchUser(userId);
    return UserEntity(id: userModel.id, name: userModel.name);
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

3. لایه ارائه

این لایه شامل UI و مدیریت دولتی منطق اینجاست که الگوی BLoC ما از BLoC برای مدیریت وضعیت و تعامل با موارد استفاده لایه دامنه استفاده می کنیم.

// presentation/bloc/user_bloc.dart
class UserBloc extends BlocUserEvent, UserState> {
  final GetUserUseCase getUserUseCase;

  UserBloc(this.getUserUseCase) : super(UserInitial());

  @override
  StreamUserState> mapEventToState(UserEvent event) async* {
    if (event is GetUserEvent) {
      yield UserLoading();
      try {
        final user = await getUserUseCase.execute(event.userId);
        yield UserLoaded(user);
      } catch (e) {
        yield UserError("Couldn't fetch user");
      }
    }
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


4. مقدمه ای بر الگوی BLoC

BLoC (جزء منطق تجاری) یک الگوی مدیریت حالت است که جدا کردن منطق ارائه را از منطق تجاری در یک برنامه فلاتر آسان می کند. اجزای اصلی الگوی BLoC عبارتند از:

  • رویدادها: اقداماتی که کاربر یا سیستم راه اندازی می کند.
  • ایالات: وضعیت رابط کاربری بر اساس رویدادها.
  • BLoC: منطق تجاری را با نگاشت رویدادها به ایالت ها مدیریت می کند.

مزیت اصلی BLoC این است که به ما اجازه می دهد رابط کاربری را از منطق جدا کنیم. BLoC به رویدادها گوش می دهد (مانند فشار دادن دکمه ها) و حالت های جدیدی را منتشر می کند که UI می تواند به آنها گوش دهد.

// Event
abstract class UserEvent {}

class GetUserEvent extends UserEvent {
  final String userId;

  GetUserEvent(this.userId);
}

// State
abstract class UserState {}

class UserInitial extends UserState {}

class UserLoading extends UserState {}

class UserLoaded extends UserState {
  final UserEntity user;

  UserLoaded(this.user);
}

class UserError extends UserState {
  final String message;

  UserError(this.message);
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


5. چرا BLoC با معماری پاک؟

استفاده از BLoC با معماری پاک تضمین می‌کند جدایی واضح بین UI و منطق تجاری، تست و نگهداری کد را آسان می کند. BLoC مسئول مدیریت انتقال‌های حالت و قوانین تجاری است، در حالی که لایه‌های معماری پاک تضمین می‌کنند که BLoC فقط با بخش‌های ضروری پایگاه کد، مانند موارد استفاده و مخازن، تعامل دارد.


6. ساختن یک اپلیکیشن فلاتر با استفاده از Clean Architecture و BLoC

اکنون، بیایید یک برنامه Flutter با استفاده از Clean Architecture و BLoC بسازیم. ما یک برنامه ساده ایجاد خواهیم کرد که داده های کاربر را از یک API واکشی می کند و آن را روی صفحه نمایش می دهد.

ساختار پروژه

lib/
├── data/
│   ├── models/
│   ├── repositories/
│   └── datasources/
├── domain/
│   ├── entities/
│   └── usecases/
├── presentation/
│   ├── bloc/
│   └── screens/
└── main.dart
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی لایه دامنه

ابتدا آن را تعریف کنید UserEntity و UserRepository.

// domain/entities/user_entity.dart
class UserEntity {
  final String id;
  final String name;

  UserEntity({required this.id, required this.name});
}

// domain/repositories/user_repository.dart
abstract class UserRepository {
  FutureUserEntity> getUser(String userId);
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بعد، ایجاد کنید GetUserUseCase برای محصور کردن منطق کسب و کار

// domain/usecases/get_user_usecase.dart
class GetUserUseCase {
  final UserRepository repository;

  GetUserUseCase(this.repository);

  FutureUserEntity> execute(String userId) {
    return repository.getUser(userId);
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی لایه داده

را تعریف کنید UserModel و مخزن را پیاده سازی کنید.

// data/models/user_model.dart
class UserModel {
  final String id;
  final String name;

  UserModel({required this.id, required this.name});

  factory UserModel.fromJson(MapString, dynamic> json) {
    return UserModel(
      id: json['id'],
      name: json['name'],
    );
  }
}

// data/repositories/user_repository_impl.dart
class UserRepositoryImpl implements UserRepository {
  final RemoteDataSource remoteDataSource;

  UserRepositoryImpl(this.remoteDataSource);

  @override
  FutureUserEntity> getUser(String userId) async {
    final userModel = await remoteDataSource.fetchUser(userId);
    return UserEntity(id: userModel.id, name: userModel.name);
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را اجرا کنید RemoteDataSource برای درخواست های شبکه

// data/datasources/remote_data_source.dart
class RemoteDataSource {
  FutureUserModel> fetchUser(String userId

) async {
    // Fake network request for simplicity
    await Future.delayed(Duration(seconds: 2));
    return UserModel(id: userId, name: 'John Doe');
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی لایه ارائه (BLoC)

ایجاد کنید UserBloc برای مدیریت دولتی

// presentation/bloc/user_bloc.dart
class UserBloc extends BlocUserEvent, UserState> {
  final GetUserUseCase getUserUseCase;

  UserBloc(this.getUserUseCase) : super(UserInitial());

  @override
  StreamUserState> mapEventToState(UserEvent event) async* {
    if (event is GetUserEvent) {
      yield UserLoading();
      try {
        final user = await getUserUseCase.execute(event.userId);
        yield UserLoaded(user);
      } catch (e) {
        yield UserError("Couldn't fetch user");
      }
    }
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی UI

اکنون، UI را با استفاده از آن پیاده سازی کنید BlocBuilder برای گوش دادن به تغییرات حالت

// presentation/screens/user_screen.dart
class UserScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('User Profile')),
      body: BlocProvider(
        create: (context) => UserBloc(GetUserUseCase(UserRepositoryImpl(RemoteDataSource()))),
        child: UserProfile(),
      ),
    );
  }
}

class UserProfile extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilderUserBloc, UserState>(
      builder: (context, state) {
        if (state is UserInitial) {
          return Center(child: Text('Press the button to fetch user data.'));
        } else if (state is UserLoading) {
          return Center(child: CircularProgressIndicator());
        } else if (state is UserLoaded) {
          return Center(child: Text('User: ${state.user.name}'));
        } else if (state is UserError) {
          return Center(child: Text(state.message));
        }
        return Container();
      },
    );
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


7. نمونه کد کامل

در اینجا کد کامل این برنامه با Clean Architecture و BLoC در Flutter آمده است:

اصلی.دارت

void main() {
  runApp(MaterialApp(
    home: UserScreen(),
  ));
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


8. تست معماری

یکی از مزایای معماری پاک این است آزمون پذیری. بیایید تست های واحد بنویسیم GetUserUseCase اطمینان حاصل شود که منطق کسب و کار همانطور که انتظار می رود کار می کند.

void main() {
  final mockUserRepository = MockUserRepository();
  final getUserUseCase = GetUserUseCase(mockUserRepository);

  test('should return user when called with a valid ID', () async {
    // Arrange
    final user = UserEntity(id: '1', name: 'John Doe');
    when(mockUserRepository.getUser(any)).thenAnswer((_) async => user);

    // Act
    final result = await getUserUseCase.execute('1');

    // Assert
    expect(result, user);
  });
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


9. بهترین روش ها و نکات پیشرفته

  • از تزریق وابستگی استفاده کنید: استفاده از بسته ای مانند را در نظر بگیرید get_it برای مدیریت وابستگی ها به روشی مقیاس پذیر.
  • از کوپلینگ محکم خودداری کنید: همیشه اطمینان حاصل کنید که منطق کسب و کار شما به چارچوب های خارجی مانند Flutter، API ها یا پایگاه داده ها بستگی ندارد.
  • جداسازی لایه ها: اطمینان حاصل کنید که رابط کاربری، منطق تجاری و داده ها در لایه های جداگانه نگهداری می شوند تا یک معماری تمیز حفظ شود.

نتیجه گیری

Clean Code Architecture و الگوی BLoC ابزارهای قدرتمندی هستند که به ساختار برنامه‌های Flutter شما کمک می‌کنند و اطمینان می‌دهند که مقیاس‌پذیر، قابل نگهداری و آزمایش‌پذیر هستند. با اجرای اصول مورد بحث در اینجا، هم مبتدیان و هم توسعه دهندگان با تجربه می توانند برنامه های کاربردی با ساختار و کیفیت بالا ایجاد کنند.

زیبایی واقعی این رویکرد در آن نهفته است انعطاف پذیری و مدولار بودن. رابط کاربری شما از منطق کسب و کار جدا شده است، و منطق کسب و کار از منابع داده جدا شده است، که گسترش یا بازسازی بخش هایی از برنامه شما را با رشد آن بسیار آسان تر می کند.

به راحتی می توانید مفاهیم معرفی شده در این مقاله را تغییر دهید و بر اساس آن کار کنید. چه در حال ساخت یک برنامه کوچک یا یک برنامه بزرگ در سطح سازمانی باشید، استفاده از Clean Architecture و BLoC شما را در مسیر نوشتن قرار می دهد. قابل نگهداری و مقیاس پذیر کد

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا