🧭 التسلسل اللي رح نمشي عليه
- Core
- Domain (Entity + Repository)
- UseCases
- Data (Model + DataSource + RepositoryImpl)
- Cubit
- UI
- main.dart
🧱 1. CORE
📁 lib/core/supabase/supabase_client.dart
🧠 شرح الملف (خارج الكود)
هذا الملف مسؤول عن:
👉 إنشاء نقطة اتصال واحدة مع Supabase لكل التطبيق
ليش مهم؟
- بدل ما تنشئ client بكل مكان
- تستخدمه مرة واحدة وتشاركه
📌 هذا يسمى:
Singleton PatternJavaScript📄 الكود:
import 'package:supabase_flutter/supabase_flutter.dart';
/// هذا الكلاس مسؤول عن:
/// - توفير SupabaseClient جاهز
/// - استخدامه في كل المشروع بدون تكرار
class SupabaseConfig {
/// static = نستخدمه بدون إنشاء object
/// final = لا يمكن تغييره
static final SupabaseClient client = Supabase.instance.client;
/// Supabase.instance → instance واحد من Supabase
/// .client → الاتصال الفعلي مع قاعدة البيانات
}JavaScript🧱 2. DOMAIN
📁 lib/features/notes/domain/entities/note.dart
🧠 شرح الملف
هذا الملف يمثل:
👉 “الملاحظة” داخل التطبيق
📌 أهم نقطة:
- لا يعرف API
- لا يعرف Supabase
- لا يعرف JSON
👉 فقط بيانات نظيفة
📄 الكود:
/// هذا الكلاس يمثل "كيان الملاحظة"
/// Entity = الشكل الرسمي للبيانات داخل التطبيق
class Note {
/// id الخاص بالملاحظة
final String id; /// عنوان الملاحظة
final String title; /// محتوى الملاحظة
final String content; /// Constructor لإنشاء Note
Note({
required this.id,
required this.title,
required this.content,
});
/// required = يجب تمرير القيمة
/// this.id = تخزين القيمة داخل المتغير
}Dart📁 domain/repository/notes_repository.dart
🧠 شرح الملف
هذا الملف هو:
👉 Contract (عقد)
يعني:
- يحدد ماذا نريد
- لا يحدد كيف
📄 الكود:
import '../entities/note.dart';
/// abstract = لا يمكن إنشاء object منه
/// هو فقط "واجهة" أو "عقد"
abstract class NotesRepository {
/// جلب كل الملاحظات
Future<List<Note>> getNotes(); /// إضافة ملاحظة
Future<void> addNote(Note note); /// حذف ملاحظة
Future<void> deleteNote(String id); /// تعديل ملاحظة
Future<void> updateNote(Note note);
}Dart🧱 3. USE CASES 🔥
📁 add_note_usecase.dart
🧠 شرح الملف
هذا الملف يمثل:
👉 عملية واحدة فقط: “إضافة ملاحظة”
📌 هنا نضع:
- القوانين
- التحقق
- business logic
📄 الكود:
import '../repository/notes_repository.dart';
import '../entities/note.dart';
/// هذا الكلاس يمثل عملية "إضافة ملاحظة"
class AddNoteUseCase {
final NotesRepository repo; /// نمرر repository -- مرجع وليس كائن أو أوبجكت
AddNoteUseCase(this.repo); /// call() تجعل الكلاس يعمل كدالة
Future<void> call(Note note) async {
/// مثال على business logic
if (note.title.isEmpty) {
throw Exception("العنوان فارغ");
} /// استدعاء repository
return await repo.addNote(note);
}
}Dart📁 get_notes_usecase.dart
import '../repository/notes_repository.dart';
import '../entities/note.dart';
class GetNotesUseCase {
final NotesRepository repo; /// نمرر repository -- مرجع وليس كائن أو أوبجكت
GetNotesUseCase(this.repo);
Future<List<Note>> call() async {
return await repo.getNotes();
}
}Dart🧱 4. DATA
📁 note_model.dart
🧠 شرح الملف
هذا الملف يحول:
JSON ↔ ObjectDart📌 الفرق:
- Entity = نظيف
- Model = يتعامل مع JSON
📄 الكود:
import '../../domain/entities/note.dart';
/// Model يرث من Entity
/// يعني هو Note + وظائف إضافية
class NoteModel extends Note {
NoteModel({
required super.id,
required super.title,
required super.content,
});
/// تحويل JSON إلى Object
factory NoteModel.fromJson(Map<String, dynamic> json) {
return NoteModel(
id: json['id'].toString(), // حل مشكلة int/String
title: json['title'],
content: json['content'],
);
}
/// تحويل Object إلى JSON
Map<String, dynamic> toJson() {
return {
/// لا نرسل id لأن Supabase يولده
'title': title,
'content': content,
};
}
}Dart📁 notes_remote_datasource.dart
🧠 شرح الملف
هذا الملف:
👉 يتعامل مباشرة مع Supabase
📄 الكود:
import 'package:supabase_flutter/supabase_flutter.dart';
import '../models/note_model.dart';
class NotesRemoteDataSource {
final SupabaseClient client;
/// dependency injection
NotesRemoteDataSource(this.client); /// جلب البيانات
Future<List<NoteModel>> getNotes() async {
final response = await client.from('notes').select();
return response.map<NoteModel>((e) {
return NoteModel.fromJson(e);
}).toList();
}
/// إضافة
Future<void> addNote(NoteModel note) async {
await client.from('notes').insert(note.toJson());
}
/// حذف
Future<void> deleteNote(String id) async {
await client.from('notes').delete().eq('id', id);
}
/// تعديل
Future<void> updateNote(NoteModel note) async {
await client
.from('notes')
.update(note.toJson())
.eq('id', note.id);
}
}Dart📁 notes_repository_impl.dart
🧠 شرح الملف
هذا الملف:
👉 يربط Domain مع Data
📄 الكود:
import '../../domain/entities/note.dart';
import '../../domain/repository/notes_repository.dart';
import '../datasource/notes_remote_datasource.dart';
import '../models/note_model.dart';
class NotesRepositoryImpl implements NotesRepository {
final NotesRemoteDataSource remote;
NotesRepositoryImpl(this.remote);
@override
Future<List<Note>> getNotes() async {
return await remote.getNotes();
}
@override
Future<void> addNote(Note note) async {
final model = NoteModel(
id: note.id,
title: note.title,
content: note.content,
); await remote.addNote(model);
}
@override
Future<void> deleteNote(String id) async {
await remote.deleteNote(id);
}
@override
Future<void> updateNote(Note note) async {
final model = NoteModel(
id: note.id,
title: note.title,
content: note.content,
); await remote.updateNote(model);
}
}Dart🧠 الخلاصة (لهذه المرحلة)
أنت الآن فهمت:
- Entity = بيانات
- Model = تحويل
- DataSource = API
- Repository = وسيط
- UseCase = منطق
🧱 5. PRESENTATION (Cubit)
📁 lib/features/notes/presentation/cubit/notes_state.dart
🧠 شرح الملف
هذا الملف يمثل:
👉 حالات التطبيق (States)
ليش مهم؟
لأن UI لازم يعرف:
- هل البيانات عم تتحمّل؟
- هل وصلت؟
- هل في خطأ؟
📄 الكود:
import '../../domain/entities/note.dart';
/// هذا هو الأب لكل الحالات
abstract class NotesState {}/// الحالة الابتدائية (قبل أي شيء)
class NotesInitial extends NotesState {}/// حالة التحميل
class NotesLoading extends NotesState {}/// حالة نجاح (فيها بيانات)
class NotesLoaded extends NotesState {
final List<Note> notes;
NotesLoaded(this.notes);
}/// حالة الخطأ
class NotesError extends NotesState {
final String message;
NotesError(this.message);
}Dart📁 notes_cubit.dart
🧠 شرح الملف
هذا أهم ملف 👇
👉 مسؤول عن:
- إدارة الحالة
- استدعاء UseCases
- إرسال States للـ UI
📄 الكود:
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../domain/entities/note.dart';
import '../../domain/usecases/get_notes_usecase.dart';
import '../../domain/usecases/add_note_usecase.dart';
import '../../domain/usecases/delete_note_usecase.dart';
import '../../domain/usecases/update_note_usecase.dart';
import 'notes_state.dart';
/// Cubit = مدير الحالة
class NotesCubit extends Cubit<NotesState> {
/// UseCases
final GetNotesUseCase getNotesUseCase;
final AddNoteUseCase addNoteUseCase;
final DeleteNoteUseCase deleteNoteUseCase;
final UpdateNoteUseCase updateNoteUseCase;
/// Constructor
NotesCubit(
this.getNotesUseCase,
this.addNoteUseCase,
this.deleteNoteUseCase,
this.updateNoteUseCase,
) : super(NotesInitial());
/// 📥 جلب البيانات
Future<void> fetchNotes() async {
emit(NotesLoading());
try {
final notes = await getNotesUseCase();
emit(NotesLoaded(notes));
} catch (e) {
emit(NotesError(e.toString()));
}
}
/// ➕ إضافة
Future<void> addNote(Note note) async {
await addNoteUseCase(note);
fetchNotes();
// تحديث
}
/// ❌ حذف
Future<void> deleteNote(String id) async {
await deleteNoteUseCase(id);
fetchNotes();
}
/// 🔄 تعديل
Future<void> updateNote(Note note) async {
await updateNoteUseCase(note);
fetchNotes();
}
}Dart🧱 6. UI📁 notes_page.dart
🧠 شرح الملف
هذه الصفحة:
👉 الصفحة الرئيسية للتطبيق
تحتوي على:
- إدخال ملاحظة
- عرض قائمة
- حذف
- انتقال لصفحة التفاصيل
📄 الكود:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../cubit/notes_cubit.dart';
import '../cubit/notes_state.dart';
import '../../domain/entities/note.dart';
import 'note_details_page.dart';
class NotesPage extends StatelessWidget {
NotesPage({super.key}); final TextEditingController titleController = TextEditingController();
final TextEditingController contentController = TextEditingController(); @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("الملاحظات")),
body: Column(
children: [
/// إدخال العنوان
TextField(controller: titleController), /// إدخال المحتوى
TextField(controller: contentController), /// زر إضافة
ElevatedButton(
onPressed: () {
final note = Note(
id: "",
title: titleController.text,
content: contentController.text,
); context.read<NotesCubit>().addNote(note);
},
child: const Text("إضافة"),
), /// عرض البيانات
Expanded(
child: BlocBuilder<NotesCubit, NotesState>(
builder: (context, state) {
/// تحميل
if (state is NotesLoading || state is NotesInitial) {
return const CircularProgressIndicator();
} /// بيانات
if (state is NotesLoaded) {
return ListView.builder(
itemCount: state.notes.length,
itemBuilder: (context, index) {
final note = state.notes[index]; return ListTile(
title: Text(note.title),
subtitle: Text(note.content), /// فتح التفاصيل
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
NoteDetailsPage(note: note),
),
);
}, /// حذف
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
context
.read<NotesCubit>()
.deleteNote(note.id);
},
),
);
},
);
} return const Text("لا يوجد بيانات");
},
),
),
],
),
);
}
}Dart📁 note_details_page.dart
🧠 شرح الملف
هذه الصفحة:
👉 تعرض الملاحظة + تسمح بالتعديل
📄 الكود:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../domain/entities/note.dart';
import '../cubit/notes_cubit.dart';
class NoteDetailsPage extends StatefulWidget {
final Note note;
const NoteDetailsPage({super.key, required this.note}); @override
State<NoteDetailsPage> createState() => _NoteDetailsPageState();
}
class _NoteDetailsPageState extends State<NoteDetailsPage> {
late TextEditingController titleController;
late TextEditingController contentController;
bool isEditing = false;
@override
void initState() {
super.initState(); /// تعبئة الحقول
titleController = TextEditingController(text: widget.note.title);
contentController = TextEditingController(text: widget.note.content);
}
void save() {
final updated = Note(
id: widget.note.id,
title: titleController.text,
content: contentController.text,
);
context.read<NotesCubit>().updateNote(updated);
Navigator.pop(context);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("تفاصيل"),
actions: [
IconButton(
icon: Icon(isEditing ? Icons.save : Icons.edit),
onPressed: () {
if (isEditing) {
save();
} else {
setState(() => isEditing = true);
}
},
)
],
),
body: Column(
children: [
TextField(
controller: titleController,
readOnly: !isEditing,
),
TextField(
controller: contentController,
readOnly: !isEditing,
),
],
),
);
}
}Dart🧱 7. main.dart
🧠 شرح الملف
هذا الملف يربط كل شيء:
👉 Dependency Injection
📄 الكود:
final datasource = NotesRemoteDataSource(client);
final repo = NotesRepositoryImpl(datasource);
final getNotes = GetNotesUseCase(repo);
final addNote = AddNoteUseCase(repo);
final deleteNote = DeleteNoteUseCase(repo);
final updateNote = UpdateNoteUseCase(repo);return NotesCubit(getNotes, addNote, deleteNote, updateNote);Dart🧠 الخلاصة النهائية
أنت الآن تملك:
✔ Clean Architecture
✔ UseCases
✔ Cubit
✔ Supabase
✔ Navigation + Edit
🧠 أولاً: شو دور UseCases (تذكير سريع)
UseCase = عملية واحدة واضحة في التطبيق
مثلاً:
- جلب الملاحظات
- إضافة ملاحظة
- حذف
- تعديل
👉 هي الطبقة بين Cubit و Repository
🧱 مكانها في المشروع
domain/
└── usecases/
├── get_notes_usecase.dart
├── add_note_usecase.dart
├── delete_note_usecase.dart
└── update_note_usecase.dartDart📁 1. get_notes_usecase.dart
🧠 شرح الملف
هذا الملف مسؤول عن:
👉 جلب جميع الملاحظات
📌 ممكن تضيف فيه لاحقاً:
- فلترة
- ترتيب
- caching
📄 الكود:
import '../repository/notes_repository.dart';
import '../entities/note.dart';
/// UseCase لجلب الملاحظات
class GetNotesUseCase {
final NotesRepository repo;
/// نمرر Repository
GetNotesUseCase(this.repo);
/// call() تسمح باستخدام الكلاس كأنه function
Future<List<Note>> call() async {
/// فقط نطلب البيانات من repository
return await repo.getNotes();
}
}Dart📁 2. add_note_usecase.dart
🧠 شرح الملف
هذا الملف مسؤول عن:
👉 إضافة ملاحظة جديدة
📌 هنا المكان الصحيح لـ:
- التحقق من البيانات
- منع القيم الفارغة
- أي business logic
📄 الكود:
import '../repository/notes_repository.dart';
import '../entities/note.dart';
/// UseCase لإضافة ملاحظة
class AddNoteUseCase {
final NotesRepository repo;
AddNoteUseCase(this.repo);
Future<void> call(Note note) async {
/// 🔴 Business Logic هنا
if (note.title.trim().isEmpty) {
throw Exception("العنوان لا يمكن أن يكون فارغ");
}
if (note.content.trim().isEmpty) {
throw Exception("المحتوى لا يمكن أن يكون فارغ");
}
/// إرسال البيانات إلى Repository
await repo.addNote(note);
}
}Dart📁 3. delete_note_usecase.dart
🧠 شرح الملف
هذا الملف مسؤول عن:
👉 حذف ملاحظة
📄 الكود:
import '../repository/notes_repository.dart';
/// UseCase لحذف ملاحظة<br>class DeleteNoteUseCase {
final NotesRepository repo;
DeleteNoteUseCase(this.repo);
Future<void> call(String id) async {
/// يمكن إضافة تحقق هنا لاحقاً<br>
if (id.isEmpty) {
throw Exception("id غير صالح");
}
await repo.deleteNote(id);
}}Dart📁 4. update_note_usecase.dart
🧠 شرح الملف
هذا الملف مسؤول عن:
👉 تعديل ملاحظة
📌 هنا تضع:
- تحقق
- قواعد تعديل
📄 الكود:
import '../repository/notes_repository.dart';
import '../entities/note.dart';
/// UseCase لتعديل ملاحظة
class UpdateNoteUseCase {
final NotesRepository repo;
UpdateNoteUseCase(this.repo);
Future<void> call(Note note) async {
/// تحقق
if (note.id.isEmpty) {
throw Exception("id غير موجود");
} if (note.title.trim().isEmpty) {
throw Exception("العنوان فارغ");
} if (note.content.trim().isEmpty) {
throw Exception("المحتوى فارغ");
} await repo.updateNote(note);
}
}Dart🔗 كيف يرتبطوا مع بعض؟
🧠 في Cubit:
await addNoteUseCase(note);
await getNotesUseCase();Dart🧠 في main.dart:
final repo = NotesRepositoryImpl(datasource);
final getNotes = GetNotesUseCase(repo);
final addNote = AddNoteUseCase(repo);
final deleteNote = DeleteNoteUseCase(repo);
final updateNote = UpdateNoteUseCase(repo);Dart💥 الخلاصة القوية
| الطبقة | مسؤوليتها |
|---|---|
| Cubit | إدارة الحالة |
| UseCase | تنفيذ العملية |
| Repository | تعريف العمليات |
| DataSource | الاتصال مع Supabase |
🚀 الآن أنت عندك:
✔ UseCases كاملة
✔ مكان واضح للـ business logic
✔ فصل نظيف بين الطبقات
رح أشرح لك:
- 🧠 كيف الملفات مرتبطة ببعض
- 🔁 كيف تمشي العملية خطوة خطوة (مثال حقيقي)
- 🎯 مين ينادي مين بالضبط
🧭 أولاً: الخريطة العامة
UI (notes_page.dart)
↓
Cubit (notes_cubit.dart)
↓
UseCase (add_note_usecase.dart)
↓
Repository (notes_repository_impl.dart)
↓
DataSource (notes_remote_datasource.dart)
↓
SupabaseDart🧠 أهم فكرة
👉 كل طبقة لا تعرف إلا الطبقة اللي تحتها فقط
🔗 العلاقات بين الملفات
🟢 1. UI
📁 notes_page.dart
context.read<NotesCubit>().addNote(note);Dart👉 UI ينادي Cubit فقط
❌ ما يعرف:
- UseCase
- Repository
- Supabase
🔵 2. Cubit
📁 notes_cubit.dart
await addNoteUseCase(note);Dart👉 Cubit ينادي UseCase
🟣 3. UseCase
📁 add_note_usecase.dart
await repo.addNote(note);Dart👉 UseCase ينادي Repository
🟡 4. Repository
📁 notes_repository_impl.dart
await remote.addNote(model);Dart👉 Repository ينادي DataSource
🔴 5. DataSource
📁 notes_remote_datasource.dart
client.from('notes').insert(...)Dart👉 DataSource ينادي Supabase
🔥 الآن نفهمها بمثال حقيقي
🎯 سيناريو: إضافة ملاحظة
🟢 STEP 1 — UI
ElevatedButton(
onPressed: () {
context.read<NotesCubit>().addNote(note);
},)Dart👉 المستخدم ضغط زر
🔵 STEP 2 — Cubit
Future<void> addNote(Note note) async {
await addNoteUseCase(note);
fetchNotes();
}Dart👉 Cubit قال:
- نفّذ العملية
- ثم حدّث البيانات
🟣 STEP 3 — UseCase
Future<void> call(Note note) async {
if (note.title.isEmpty) throw Exception();
await repo.addNote(note);
}Dart👉 تحقق + تنفيذ
🟡 STEP 4 — Repository
final model = NoteModel(...);
await remote.addNote(model);Dart👉 تحويل Entity → Model
🔴 STEP 5 — DataSource
await client.from('notes').insert(...)Dart👉 إرسال إلى Supabase
🟢 يرجع الرد بالعكس 🔁
Supabase → DataSource → Repository → UseCase → Cubit → UIDart🧠 سيناريو جلب البيانات
UI
BlocBuilder(...)DartCubit
fetchNotes()DartUseCase
getNotesUseCase()DartRepository
remote.getNotes()DartDataSource
select()Dartيرجع:
emit(NotesLoaded(notes));Dart💡 ليش هذا التقسيم عبقري؟
🎯 1. فصل المسؤوليات
| طبقة | عملها |
|---|---|
| UI | عرض فقط |
| Cubit | إدارة الحالة |
| UseCase | منطق |
| Repository | واجهة |
| DataSource | API |
🎯 2. سهولة التغيير
مثلاً:
👉 بدك تغير Supabase إلى Firebase؟
✔ تغير DataSource فقط
❌ باقي المشروع لا يتغير
🎯 3. Testing سهل
- تختبر UseCase لوحده
- تختبر Cubit لوحده
🔥 ملخص ذهني سريع
UI ما يعرف إلا Cubit
Cubit ما يعرف إلا UseCase
UseCase ما يعرف إلا Repository
Repository ما يعرف إلا DataSource
DataSource يعرف SupabaseDart👉 مو في 2 Repository حقيقيين
👉 في واحد (واجهة) + واحد (تنفيذ)
🧠 خلّينا نفكها بهدوء
🔷 1. هذا مو Repository فعلي
📁 notes_repository.dart
abstract class NotesRepository {
Future<List<Note>> getNotes();
}Dart🎯 هذا اسمه:
Contract / InterfaceDart🧠 شو يعني؟
👉 يقول:
“أنا بدي هيك عمليات”
لكن ❌ ما يقول كيف تنفذ
🔶 2. هذا هو Repository الحقيقي
📁 notes_repository_impl.dart
class NotesRepositoryImpl implements NotesRepository {Dart🎯 هذا اسمه:
ImplementationDart🧠 شو يعمل؟
👉 ينفذ العمليات باستخدام:
DataSource (Supabase)Dart🔥 ليش عملنا هيك؟
🎯 السبب الأساسي:
Decoupling (فصل الطبقات)Dart🧠 بدون هذا الفصل ❌
Cubit → Supabase مباشرةDart👉 كارثة 😅
🧠 مع الفصل ✅
Cubit → UseCase → Repository (Interface)
↓
RepositoryImpl
↓
DataSourceDart🎯 الفائدة
1️⃣ تقدر تغيّر المصدر بسهولة
اليوم:
SupabaseDartبكرة:
Firebase
Local DB
APIDart👉 فقط تغيّر:
NotesRepositoryImplDart2️⃣ Testing سهل 🔥
تقدر تعمل:
FakeNotesRepositoryDartبدون Supabase
3️⃣ Clean Architecture حقيقي
🧠 مثال بسيط يوضح الفكرة
Interface:
abstract class Animal {
void sound();
}DartImplementation:
class Dog implements Animal {
void sound() => print("woof");
}Dart👉 نفس الفكرة بالضبط
🔥 الخلاصة
| الملف | دوره |
|---|---|
| notes_repository.dart | تعريف (Interface) |
| notes_repository_impl.dart | تنفيذ (Implementation) |
💡 قاعدة ذهبية
Domain يعرف Interface فقط
Data يعرف ImplementationDartcall شو عملها ???
👌 وهذا من أهم الأشياء اللي لازم تفهمها في UseCases 🔥
🧠 شو هي call() في Dart؟
ببساطة:
call() = تخلي الكلاس يشتغل كأنه functionDart🎯 مثال بسيط جداً
بدون call ❌
class Test {
void execute() {
print("Hello");
}
}Dartالاستخدام:
final t = Test();
t.execute(); // لازم تكتب اسم الميثودDartمع call ✅
class Test {
void call() {
print("Hello");
}
}Dartالاستخدام:
final t = Test();
t(); // 🔥 كأنه functionDart💥 هذا هو السر
وجود call() داخل الكلاس = يسمح لك تناديه كدالةDart🧩 كيف استخدمناه في UseCase
📁 add_note_usecase.dart
class AddNoteUseCase {
final NotesRepository repo;
AddNoteUseCase(this.repo);
Future<void> call(Note note) async {
await repo.addNote(note);
}
}Dart🧠 الاستخدام في Cubit
await addNoteUseCase(note);Dart❗ شو صار هون؟
Dart فهمها كأنك كتبت:
await addNoteUseCase.call(note);Dart🔥 ليش نستخدم call؟
🎯 1. شكل أنظف
بدل:
addNoteUseCase.execute(note);Dartنكتب:
addNoteUseCase(note); // أجمل وأبسطDart🎯 2. يخلّي UseCase كأنه function
وهذا الهدف أصلاً:
UseCase = عملية واحدة = FunctionDart🎯 3. أسلوب Clean Architecture
معظم المشاريع الكبيرة تستخدم:
call()Dart🧠 ملاحظة مهمة
call ليست كلمة محجوزة ❌
لكن Dart يعطيها ميزة خاصة ✅
⚠️ بدون call
لازم تكتب:
addNoteUseCase.call(note);Dart💡 مثال أقوى
class Sum {
int call(int a, int b) {
return a + b;
}
}Dartالاستخدام:
final s = Sum();
print(s(2, 3)); // 5 🔥Dart🔥 الخلاصة
| الشي | المعنى |
|---|---|
| call() | دالة خاصة داخل الكلاس |
| فائدتها | تخلي الكلاس callable |
| النتيجة | كأنه function |