| نمط التعرض المعماري | الخصائص والآلية البرمجية | التأثير على أمان وصيانة التطبيق |
|---|---|---|
| كشف الإشارة القابلة للكتابة مباشرة (Writable Exposed) | السماح للمكونات الخارجية بالوصول المباشر لتعديل الإشارة عبر `.set()` أو `.update()` | يخلق اقترانًا خطيرًا ويفقد النظام السيطرة على تدفق البيانات وتتبع الأخطاء |
| استخدام asReadonly (Readonly Public API) | إخفاء الإشارة الأصلية كخاصية خاصة واستخدام دالة `.asReadonly()` لتوفير واجهة قراءة آمنة فقط | يضمن تغليف البيانات هندسياً ويجبر المكونات على التعديل حصرياً عبر الدوال المعتمدة في الخدمة |
| استخدام Getters التقليدية لإرجاع النسخ | الاعتماد على دوال جلب عادية تُرجع نسخة من البيانات أو قيمة مجردة | مقبول ولكنه يفتقر للتفاعل المباشر الذي توفره نظام الإشارات الحديثة في أنگولر مقارنة بـ Readonly Signals |
في معمارية Angular 22.1 المتقدمة، يُعد الحفاظ على أمان البيانات داخل الخدمات (Services) ركيزة أساسية لضمان عدم حدوث تعديلات عشوائية أو غير مسؤولة على الحالة. عبر استخدام نمط الـ WritableSignal داخلياً مع تعريضها للخارج بصيغة ReadonlySignal باستخدام دالة asReadonly()، نضمن تطبيق مبدأ تغليف البيانات (Encapsulation) بشكل هندسي صارم يمنع أي مكون خارجي من العبث بالحالة مباشرة.
تسمح لك هذه التقنية بالإعلان عن الإشارة كـ private أو مخفية داخل الخدمة بصيغة قابلة للتعديل، ثم توفير واجهة قراءة عامة (Public Readonly API) للمكونات، مما يمنع حدوث أخطاء برمجية ناتجة عن تعديل الحالة من أماكن غير متوقعة.
عندما تقتصر صلاحية تعديل الحالة على الخدمة نفسها، يصبح تتبع الأخطاء وتتبع التغييرات في النظام أمراً يسيراً وواضحاً للغاية.
| 1 | import { Injectable, signal } from '@angular/core'; |
| 2 | |
| 3 | @Injectable({ |
| 4 | providedIn: 'root' |
| 5 | }) |
| 6 | export class SecureUserService { |
| 7 | // إشارة خاصة قابلة للكتابة داخل الخدمة فقط |
| 8 | private currentUserSignal = signal<string>('مهندس غير مصرح له'); |
| 9 | |
| 10 | // تعريض الإشارة للخارج كـ Readonly لمنع التعديل الخارجي المباشر |
| 11 | readonly currentUser = this.currentUserSignal.asReadonly(); |
| 12 | |
| 13 | updateUser(newName: string) { |
| 14 | if (newName.trim().length > 0) { |
| 15 | this.currentUserSignal.set(newName); |
| 16 | } |
| 17 | } |
| 18 | } |
| 1 | <!-- secure-profile.component.html --> |
| 2 | <div class="secure-box"> |
| 3 | <h3>لوحة الملف الشخصي المحمي</h3> |
| 4 | <p>المستخدم الحالي في النظام: <strong>{{ userService.currentUser() }}</strong></p> |
| 5 | |
| 6 | <div class="input-group"> |
| 7 | <input #nameInput type="text" placeholder="أدخل الاسم الجديد..." class="secure-input" /> |
| 8 | <button (click)="changeName(nameInput.value)" class="secure-btn">تحديث الاسم بأمان</button> |
| 9 | </div> |
| 10 | </div> |