پرشین تم مقالات آموزش معماری Bloc در فلاتر

آموزش معماری Bloc در فلاتر

image profile پرشین تم - 09 مهر 1404 - 16:31 دانلود مقاله

معماری BLoC (مخفف Business Logic Component) یکی از محبوب‌ترین معماری‌ها در فلاتر برای مدیریت وضعیت (state management) است. این معماری به تفکیک منطق کسب‌وکار از رابط کاربری کمک می‌کند و باعث می‌شود کدها قابل تست، قابل نگهداری و قابل توسعه باشند.

آموزش معماری Bloc در فلاتر

🧠 اجزای اصلی معماری BLoC

1. Event (رویدادها)

رویدادهایی هستند که از سمت UI به BLoC ارسال می‌شوند. مثلاً:

  • کاربر روی دکمه کلیک می‌کند
  • اسکرول به انتهای لیست می‌رسد
  • فرم ارسال می‌شود
class FetchProducts extends ProductEvent {}

2. State (وضعیت‌ها)

نمایانگر وضعیت فعلی اپلیکیشن هستند. UI بر اساس State تغییر می‌کند.

class ProductLoading extends ProductState {}
class ProductLoaded extends ProductState {
  final List<Product> products;
}

3. Bloc (منطق کسب‌وکار)

واسط بین Event و State است. وقتی Event دریافت می‌شود، BLoC آن را پردازش کرده و یک State جدید تولید می‌کند.

on<FetchProducts>((event, emit) async {
  emit(ProductLoading());
  final products = await repository.fetchProducts();
  emit(ProductLoaded(products));
});

4. UI (رابط کاربری)

با استفاده از BlocBuilder یا BlocListener به تغییرات State واکنش نشان می‌دهد.

BlocBuilder<ProductBloc, ProductState>(
  builder: (context, state) {
    if (state is ProductLoading) return CircularProgressIndicator();
    if (state is ProductLoaded) return ListView(...);
    return Text('خطا');
  },
)

 

🎯 مزایای معماری BLoC

  • جداسازی کامل UI از منطق
  • مناسب برای پروژه‌های بزرگ
  • قابل تست بودن منطق
  • استفاده از Stream برای مدیریت داده‌ها

 

در ادامه یک مثال عملی را با هم بررسی می کنیم:

 

📁 ساختار پوشه‌ها

lib/
├── blocs/
│   └── product/
│       ├── product_bloc.dart
│       ├── product_event.dart
│       └── product_state.dart
│
├── models/
│   └── product.dart
│
├── repositories/
│   └── product_repository.dart
│
├── screens/
│   └── product_list_screen.dart
│
├── widgets/
│   └── product_list_item.dart
│
├── main.dart

 

📦 پکیج‌های مورد نیاز برای مثال

1. flutter_bloc

برای استفاده از کلاس‌های Bloc, BlocBuilder, BlocProvider, BlocListener و مدیریت وضعیت‌ها.

dependencies:
  flutter_bloc: ^8.1.3

2. equatable

برای مقایسه راحت‌تر بین Event و State بدون نیاز به نوشتن دستی == و hashCode.

dependencies:
  equatable: ^2.0.5

3. (اختیاری برای تست) bloc_test و mocktail

اگر بخوای تست‌هایی مثل blocTest یا تست ویجت بنویسی، این‌ها لازم می‌شن:

dev_dependencies:
  bloc_test: ^9.1.0
  mocktail: ^1.0.0

 

🧱 ساختار کلی BLoC

1. ProductEvent

abstract class ProductEvent {}

class FetchProducts extends ProductEvent {
  final int page;
  FetchProducts(this.page);
}

class AddToFavorites extends ProductEvent {
  final Product product;
  AddToFavorites(this.product);
}

 

2. ProductState

abstract class ProductState {}

class ProductInitial extends ProductState {}

class ProductLoading extends ProductState {}

class ProductLoaded extends ProductState {
  final List<Product> products;
  final bool hasReachedMax;
  ProductLoaded({required this.products, required this.hasReachedMax});
}

class ProductError extends ProductState {
  final String message;
  ProductError(this.message);
}

 

3. ProductBloc

class ProductBloc extends Bloc<ProductEvent, ProductState> {
  final ProductRepository repository;
  int currentPage = 1;
  bool isFetching = false;

  ProductBloc(this.repository) : super(ProductInitial()) {
    on<FetchProducts>(_onFetchProducts);
    on<AddToFavorites>(_onAddToFavorites);
  }

  Future<void> _onFetchProducts(FetchProducts event, Emitter<ProductState> emit) async {
    if (isFetching) return;
    isFetching = true;
    try {
      final currentState = state;
      List<Product> oldProducts = [];
      if (currentState is ProductLoaded) {
        oldProducts = currentState.products;
      }

      final newProducts = await repository.fetchProducts(event.page);
      final hasReachedMax = newProducts.isEmpty;

      emit(ProductLoaded(
        products: oldProducts + newProducts,
        hasReachedMax: hasReachedMax,
      ));
      currentPage++;

    } catch (e) {
      emit(ProductError(e.toString()));
    }

    isFetching = false;
  }

  void _onAddToFavorites(AddToFavorites event, Emitter<ProductState> emit) {
    // اینجا می‌تونی محصول رو به لیست علاقه‌مندی‌ها اضافه کنی یا API بزنی
    // مثلا: repository.addToFavorites(event.product);
  }
}

 

4.Repository

class ProductRepository {
  Future<List<Product>> fetchProducts(int page) async {
    // API call برای دریافت محصولات
  }

  Future<void> addToFavorites(Product product) async {
    // API call برای افزودن به علاقه‌مندی‌ها
  }
}

 

🎯 پیاده‌سازی ویجت لیست محصولات

class ProductListWidget extends StatefulWidget {
  const ProductListWidget({Key? key}) : super(key: key);
  @override
  State<ProductListWidget> createState() => _ProductListWidgetState();
}

class _ProductListWidgetState extends State<ProductListWidget> {
  final ScrollController _scrollController = ScrollController();
  late ProductBloc _productBloc;

  @override
  void initState() {
    super.initState();
    _productBloc = context.read<ProductBloc>();
    _productBloc.add(FetchProducts(1)); // بارگذاری اولیه
    _scrollController.addListener(() {
      if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200) {
        final state = _productBloc.state;
        if (state is ProductLoaded && !state.hasReachedMax) {
          _productBloc.add(FetchProducts(_productBloc.currentPage));
        }
      }
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<ProductBloc, ProductState>(
      builder: (context, state) {
        if (state is ProductLoading && _productBloc.currentPage == 1) {
          return const Center(child: CircularProgressIndicator());
        } else if (state is ProductLoaded) {
          return ListView.builder(
            controller: _scrollController,
            itemCount: state.products.length + 1,
            itemBuilder: (context, index) {
              if (index < state.products.length) {
                final product = state.products[index];
                return ListTile(
                  leading: Image.network(product.imageUrl),
                  title: Text(product.name),
                  subtitle: Text('${product.price} تومان'),
                  trailing: IconButton(
                    icon: const Icon(Icons.favorite_border),
                    onPressed: () {
                      _productBloc.add(AddToFavorites(product));
                      ScaffoldMessenger.of(context).showSnackBar(
                        SnackBar(content: Text('${product.name} به علاقه‌مندی‌ها اضافه شد')),
                      );
                    },
                  ),
                );
              } else {
                return state.hasReachedMax
                    ? const SizedBox.shrink()
                    : const Padding(
                        padding: EdgeInsets.all(16.0),
                        child: Center(child: CircularProgressIndicator()),
                      );
              }
            },
          );
        } else if (state is ProductError) {
          return Center(child: Text('خطا: ${state.message}'));
        } else {
          return const SizedBox.shrink();
        }
      },
    );
  }
}

 

✅ نکات مهم

  • از ScrollController برای تشخیص رسیدن به انتهای لیست استفاده شده.
  • در BlocBuilder وضعیت‌ها بررسی می‌شوند: بارگذاری، موفق، خطا.
  • دکمه علاقه‌مندی با dispatch کردن AddToFavorites کار می‌کند.
  • اگر hasReachedMax == true باشد، دیگر بارگذاری انجام نمی‌شود.

 

✅ مزایای این ساختار

  • تفکیک مسئولیت‌ها: هر بخش وظیفه خاصی دارد
  • قابل تست و توسعه: راحت می‌توان تست نوشت یا قابلیت جدید اضافه کرد
  • خوانایی بالا: توسعه‌دهندگان دیگر به‌راحتی می‌توانند پروژه را دنبال کنند
با خرید اشتراک می توانید تا چندین برابر مبلغ خرید اشتراک خود قالب های HTML ، سورس کدهای آماده و یا مقالات دانلود کنید
شما می توانید تنها فقط با مبلغ 3,000,000 میلیون تومان وب سایت سفارسی برای خود داشته باشید
محبوب ترین مقالات
تفاوت بین CSS و SCSS چیست؟ تفاوت بین CSS و SCSS چیست؟
category برنامه نویسی 07 اسفند 1402
تفاوت بین RDBMS و DBMS تفاوت بین RDBMS و DBMS
category برنامه نویسی 02 فروردین 1403
کاوش در معماری GPT-3 کاوش در معماری GPT-3
category هوش مصنوعی 12 اسفند 1402
کلمات کلیدی در SQL کلمات کلیدی در SQL
category برنامه نویسی 01 خرداد 1403
تفاوت بین CSS، SASS و SCSS چیست؟ تفاوت بین CSS، SASS و SCSS چیست؟
category برنامه نویسی 13 اسفند 1402
انواع Join در SQL انواع Join در SQL
category برنامه نویسی 02 فروردین 1403
ChatGPT چیست؟ ChatGPT چیست؟
category هوش مصنوعی 12 اسفند 1402
آخرین مقالات
میکروسرویس چیست؟ مثال عملی در Asp Core میکروسرویس چیست؟ مثال عملی در Asp Core میکروسرویس‌ها (Microservices) یک سبک معماری نرم‌افزاری هستند که در آن سیستم بزرگ به مجموعه‌ای از سرویس‌های کوچک، مستقل...
category برنامه نویسی 09 مهر 1404
Redis چیست؟ آموزش استفاده از آن در asp core Redis چیست؟ آموزش استفاده از آن در asp core Redis یک مخزن داده با عملکرد بالا و کلید-مقدار در حافظه است که اغلب برای ذخیره‌سازی موقت (caching)، مدیریت جلسه (sessi...
category برنامه نویسی 27 شهریور 1404
CI-CD در فلاتر چیست؟ CI-CD در فلاتر چیست؟ در توسعه فلاتر، CI/CD مخفف Continuous Integration (ادغام مداوم) و Continuous Delivery/Deployment (تحویل/استقرار مداوم)...
category برنامه نویسی 25 شهریور 1404