MVC יחד עם עוד כמה תבניות כמו MVVM נחשבת יותר כתבנית ארכיטקטורה ולא כתבנית עיצוב
קלאסית, אבל לנו לא משנה הפילוסופיה אלא התכל’ס ולכן נציג אותה כרגיל בצורה הפשוטה
ביותר.
אקדים ואומר שזה רלוונטי בעיקר למתחי WEB ששם התבנית מיושמת היום היטב ופחות באפליקציות
דסקטופ (בוודאי אפליקציות מהדור החדש) בטכנולוגיות Microsoft
כך או כך הבנת השיטה יכולה לתרום הרבה למפתחים מתחילים על תכנון מערכת
ועל תקשורת בין שכבות.. אני אישית פגשתי את MVC לפני שידעתי כלום על תבניות עיצוב וזה שדרג
בהרבה את החשיבה שלי על העולם התכנוני.
אז מה זה MVC? הרעיון אומר הפרדת צד הלקוח לגמרי מצד השרת וכל
התקשורת ביניהם תהיה באמצעות מרכז פיקוח שנקרא Controller.
התרשים הברור ביותר ייראה כך (בתור התחלה)
אבל רגע, מצאתי תרשים חמוד.. שממחיש בצורה קצת שונה את התבנית. יש לנו מסך משתמש, יש לנו קופסת נתונים אטומה, ורכיב תקשורת באמצע.
כהסבר בסיסי נגיד שהמודל שמבחינתי מייצג עכשיו את הכל חוץ מאשר הUI
ז”א הגדרת יישויות , Dal, BL , ואילו הUI הוא משהו פשוט שכל מה שהוא מכיר זה הקונטרולר ודרכו הוא מדבר עם שאר
העולם, מה זה נותן לי? ובכן שימוש חוזר
החלפת UI לUI עדכני יותר,
שמירה על מבנה שכבות, ועוד ועוד.
אבל זה ברמה בסיסית, ברמה
מורכבת יותר גם הView יכול להכיראת הModel , אמנם הוא לא פונה אליו אבל הוא יכול לדוגמא
ליירטEvents שנורים ע”י שכבה כלשהי במערכת שלנו (המודל
נניח),
מצב כזה יוצר תלות מסויימת, אבל לא קריטית.(לדוגמא החלפת הView לגרסה מתקדמת תחייב רישום לאירועים בView החדש)
רוצים הסבר נוסף? בבקשה. ניתן להציג את הקונטרולר כמתווך בין השכבות,
כי אם אנו מסכימים שאפליקציה מבוזרת זה טוב וחיוני (אוי לכם אם לא) וכתוצאה מזה
אנו מאמצים שיטה מודולרית
של שכבות בתכנית נניח Dal=>BL=>UI עדיין ישנה בעייתיות
גדולה מי מכיר את מי ואיך המודולים
מתקשרים ביניהם! , בוואקום הזה נדחפת MVC ומציעה פתרון
לתקשורת בין השכבות שתקרא controllerController
ה מכיר
את כולם, והוא singletone , כולם מכירים אותו והכל
דופק נפלא.
את
הבעיות של MVC אני לא אציג כאן כדי לא להרוס את החגיגה, מה שכן
אני אציג מיני אפליקציה שמדגימה את התבנית, בהמשך (פוסט הבא) אציג דוגמא מוחשית
יותר (Real World Sample) שתציג את ASP MVC כפי שמוטמעת היום בVisual
Studio וזה סוג של סטנדרט.
דוגמא:
אני אבנה את הדוגמא לפי עיקרון ה Inversion of control שמוכר גם כ IOC, ויזכה לפוסט נפרד בעתיד
בינתיים ניתן להחכים קצת באמצעות Depndency Injection שזה חלק מIOC
1. נגדיר חוזה לקונטרולר , הוא אמור לכלול את החתימות שאני רוצה לתמוך
בהם לאורך האפליקציה , נוח לי לעבוד עם interface אבל לא חובה.
public
interface IController
{
void
AddItem(Item item);
List<Item> GetItems();
}
2. אני מגדיר דבר ראשון חוזה Imodel שיכיל את מה שהמודל יודע
לעשות
public interface IModel
{
void
AddItem(Item item);
IEnumerable<Item> GetItems();
}
3.
נגדיר
חוזה לIview, רק
נזכור שכל view שירוץ אצלינו צריך להיות מסוג IView,
חשוב
לשים לב לחתימה InjectController שארחיב עליה עוד מעט.
public interface IModel
{
void
AddItem(Item item);
IEnumerable<Item> GetItems();
void InjectController(IController controller);
}
לפני
שנמשיך באותה רמה של החוזים נגדיר את האובייקט שהמודל מטפל בו, קראתי לו
אייטם
והוא נראה כך:
public class Item
{
public string name { get; set; }
}
4. אני מגדיר אובייקט מודל שבשבילי זה כל מה שיושב בצד שרת גם הלוגיקה
וגם הנתונים, והוא כמובן המימוש של Imodel.
public class Model
:IModel
{
public Model()
{
}
List<Item> Items = new List<Item>();
public void AddItem(Item item)
{
if (!Items.Contains(item))
Items.Add(item);
}
public IEnumerable<Item> GetItems()
{
ReadOnlyCollection<Item>
returendList = new ReadOnlyCollection<Item>(Items);
return returendList;
}
}
5.
נגדיר את
המימוש הקונקרטי של הקונטרולר, הוא יכיל אינסטנסים מסוג Iview ו Imodel
ויצור את
ההתקשרות ביניהם, הכיף הגדול הוא כמובן שהוא(הקונטרולר) לא מכיר את המימוש הספציפי
! מה שכן הוא יודע לטפל בתקשורת בין כל מי שהוא IModel למי שהוא IView (טוב בלי להיסחף, אבל זה על גבול המרגש !)
public sealed class
Contreoller : IController
{
public Contreoller(IView view, IModel model)
{
_View = view;
_Model = model;
}
private IView _View;
private IModel _Model;
public List<Item> GetItems()
{
return _Model.GetItems().ToList();
}
public void AddItem(Item item)
{
_Model.AddItem(item);
}
}
6.
מה נשאר
לנו? כמובן VIEW.. מפאת עצלנותי לא אגדיר עכשיו טפסי UI
אני
מגדיר קלאס גאוני שעובד מול console ומבחינתי עכשיו הוא הVIEW וכמובן הוא
המימוש
של Iview,
לא לפספס
נקודה חשובה: הView מחזיק אינסטנס של controller וגם הcontroller
מחזיק אינסטנס של הview
זה הגיוני מאוד כי אני רוצה לשלוח בקשות ולקבל תשובות,
התשובות
האלה הם בעצם הCallBack
של הקונטרולר לצד הUI.
בכל מקרה
כך ייראה הView :
public class DeomView
: IView
{
IController _controller;
public DeomView()
{
}
public void ShowItems(List<Item>
list)
{
if(_controller != null)
foreach (var item in list)
{
Console.WriteLine(item.name);
}
}
public void addItem()
{
if (_controller != null)
{
Console.WriteLine(“enter
Name for new item”);
Item item = new Item() { name = Console.ReadLine()
};
_controller.AddItem(item);
}
}
public void InjectController(IController controller)
{
this._controller = controller;
}
}
7. וזהו, בוא נריץ את העניינים,
על הדרך פתרנו בעיה מעיקה מי מרים את מי, ז”א ברור לנו מי מכיר את מי אבל אני
לא הייתי רוצה שהקונטרולר ירים את המודל או הView ירים את הקונטרולר,
במצב
הנוכחי אני משתמש בconsole שיוצר את כולם ושולח להם
את המופעים הרלוונטיים.
class
Program
{
static void Main(string[] args)
{
IView view = new DeomView();
IModel model = new
Model();
IController control = new
Contreoller(view, model);
view.InjectController(control);
view.addItem();
view.addItem();
view.ShowItems(control.GetItems());
}
}
8.
הערה
אחרונה(למבוגרים בלבד) וממש חשובה, זוכרים את הפתיחה אודות IOC
וDependency Injection ??
אז הפונקציה של הView שנקראת InjectController זה המחשה מצוינת לבעיה ולפתרונה, כאמור
אמרנו שהview מכיר controller וגם להיפך הcontroller מכיר view אבל איך אני מוודא שיש לי
אינסטנסים שלהם בזמן ריצה?
ז”א
אם נבקש בקונסטרקטור של הview מופע של controller, לא יהיה לי מה לשלוח כי
הcontroller לא נוצר, והסיבה שהוא לא נוצר היא פשוט כי
כדי ליצור אותו יש לי צורך לספק לו בקונסטרקטור מופע של view שעדיין לא הרמתי !!
ז”א הם תלויים זה בזה ..
מצער
מאוד אה? יפה לכן הוספנו פונקציה של injection שנקרא לה דבר ראשון לפני
שנשתמש ביכולת של הview והיא “מזריקה”
לתוך הview את הקונטרולר והכל מסודר.
מסובך?
קצת.. תקראו שוב מהתחלה זה יהיה יותר טוב.. (אצלי זה עבד)
מדהים! פשוט ומשעשע , תמשיך, פעם ראשונה הבנתי מה זה MVC
Good Work, and Fun too..
יש קשר בין IOC ל ASP MVC???
תגיד – אתה מורה? אם לא זה ברכה לבטלה!!
מורה בשעות הפנאי
תודה
yes it is. great Post !
וואלה הרב דוט נט השני..