تبیین مفهوم الگوی حالت در فلاتر

الگوی حالت به عنوان یک الگوی طراحی رفتاری عمل می کند که به کپسوله کردن رفتارهای مختلف برای یک شی با توجه به وضعیت داخلی آن کمک می کند. این به یک شی اجازه می دهد تا رفتار خود را به صورت پویا بدون تکیه بر عبارات شرطی تغییر دهد و در نهایت قابلیت نگهداری را افزایش دهد.
باز کردن ذات الگوی دولت
همانطور که در منبع Design Patterns in Dart آمده است، الگوی حالت به عنوان یک الگوی طراحی رفتاری محوری در محصور کردن رفتارهای متنوع برای یک شی بر اساس وضعیت داخلی آن عمل می کند. با این رویکرد، یک شی می تواند رفتار خود را به صورت پویا و بدون نیاز به عبارات شرطی تنظیم کند، در نتیجه پایگاه کد را ساده می کند.
اساساً، هر حالت یک شی با کلاسهای مجزا نشان داده میشود، که بهعنوان پسوند یا تغییرات یک کلاس حالت اصلی خاص برای آن شی عمل میکنند.
غواصی عمیق تر در مفهوم
داشتن یک شی مانند را در نظر بگیرید Water
، جایی که شما a را تعریف می کنید WaterState
برای تجسم تغییراتی مانند Solid
، Liquid
، و Gaseous
:
abstract class WaterState {
//
}
class Solid extends WaterState {
//
}
class Liquid extends WaterState {
//
}
class Gaseous extends WaterState {
//
}
علاوه بر این، الگوی حالت به یک جزء حیاتی از الگوی BLoC تبدیل می شود. اگر از الگوی BLoC استفاده می کنید، اساساً از الگوی حالت استفاده می کنید.
سناریوهای ایده آل برای اجرای الگوی دولتی
الگوی State در شرایط زیر مفید است:
- وقتی یک شی بر اساس حالتش رفتار متفاوتی دارد.
- اگر تعداد حالت ها قابل توجه باشد و تغییرات حالت مکرر باشد.
- وقتی یک کلاس دارای چندین شرط است که بر رفتار آن مربوط به مقادیر فیلد تأثیر می گذارد.
- در مواردی که کد تکراری قابل توجهی برای حالت ها و انتقال های مشابه وجود دارد.
کاربرد الگوی حالت در زندگی واقعی
بیایید اکنون یک مثال عملی را بررسی کنیم که الگوی حالت را در عمل نشان می دهد. کلاس زیر را در نظر بگیرید، جایی که تعاریف حالت شامل متغیرهای و ChangeNotifier
:
class CategoryStore extends ChangeNotifier {
List<String> categories = [];
bool isLoading = false;
String error = '';
IApiDatasource apiDatasource = ApiDatasource();
void getCategories() async {
isLoading = true;
await apiDatasource.getCategories().then((response) {
response.fold(
(left) => error = left.message,
(right) => categories = right,
);
});
isLoading = false;
notifyListeners();
}
}
را fold()
روش مشخص شده در بالا با نوع هر یک مرتبط است، یک عنصر اساسی در برنامه نویسی تابعی که نشان دهنده مقداری است که تحت یکی از دو نوع مشخص شده قرار می گیرد. به طور معمول، یا یک مقدار موفق یا ناموفق را نشان می دهد، دقیقاً مانند مثالی که در آن وجود دارد left
نشان دهنده مقدار خطا و right
ارزش موفقیت را نشان می دهد.
در کلاس فوق، یک تابع بارگذاری را آغاز می کند isLoading
، سپس اقدام به واکشی داده ها از یک API می کند و آن را در آن ذخیره می کند categories
متغیر. پس از اتمام بارگذاری، تابع مقدار را به false تنظیم می کند.
برای ساده سازی این کد با استفاده از الگوی حالت، ساختار آن را به صورت زیر انجام می دهیم:
تعریف طبقات دولتی
حالت ها و کلاس های مربوط به آنها در ابتدا اعلام می شوند:
abstract class CategoryState {}
class CategoryInitial extends CategoryState {}
class CategoryLoading extends CategoryState {}
class CategoryLoaded extends CategoryState {
final List<String> categories;
CategoryLoaded(this.categories);
}
class CategoryError extends CategoryState {
final String message;
CategoryError(this.message);
}
پالایش کلاس فروشگاه
در getCategories()
تابع، ما حذف isLoading
متغیر و معرفی کنید value
متغیر، نشان دهنده وضعیت درون است ValueNotifier
و پایبندی به CategoryState
. در نتیجه، CategoryLoading
برای نشان دادن ایالت ما تعیین شده است.
متعاقبا، در fold()
روش، اگر درخواست باطل شد، value
انتقال به Error
وضعیت حامل پیام خطا (left
). برعکس، پس از یک نتیجه موفق، آن را اتخاذ می کند Loaded
حالت با داده های موجود در right
متغیر. این گردش کار، categories
و error
متغیرها:
class CategoryStore extends ValueNotifier<CategoryState> {
CategoryStore() : super(CategoryInitial());
IApiDatasource apiDatasource = ApiDatasource();
void getCategories() async {
value = CategoryLoading();
await apiDatasource.getCategories().then((response) {
response.fold(
(left) => value = CategoryError(left.message),
(right) => value = CategoryLoaded(right),
);
});
}
}
را value
گیرنده مربوط می شود ValueNotifier
، وضعیت فعلی کلاس فروشگاه ما را در خود جای داده است.
نمایش یک نمونه در یک صفحه
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// CategoryStore instance establishment
CategoryStore store = CategoryStore();
// Initialization function upon page load
@override
void initState() {
store.getCategories();
super.initState();
}
@override
void dispose() {
super.dispose();
store.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Expanded(
// Observing the store
child: ValueListenableBuilder(
valueListenable: store,
builder: (context, value, child) {
// Error handling
if (value is CategoryError) {
return Center(
child: Text(
'Error loading categories: ${value.message}',
),
);
}
// Presenting loaded data
if (value is CategoryLoaded) {
return ListView.builder(
itemCount: value.categories.length,
itemBuilder: (context, index) {
final category = value.categories[index];
return Text(category);
},
);
}
// Display loading status
return const Center(child: CircularProgressIndicator());
},
),
),
);
}
}
به این ترتیب، ما الگوی حالت را با موفقیت پیاده سازی کرده ایم! از طریق این رویکرد، ما به مسئولیت واحد و اصول باز/بسته پایبند هستیم و کد را با حذف عبارات شرطی که در غیر این صورت میتوانند پایگاه کد را پیچیده کنند، سادهسازی میکنیم.
بسته بندی
سفر شما از طریق این کاوش الگوی ایالت بسیار قدردانی می شود. در حالی که تمرکز روی خود الگوی ایالت بود، من از عمیقتر کردن عناصری مانند آن خودداری کردم ValueNotifier
و سایر موارد استفاده شده در مثال.