510 likes | 521 Views
Implementing Interfaces. Agenda. Declaring Interfaces Implementing Multiple Interfaces Virtual Implementing Interface Methods .NET Build-IN Interfaces. Agenda. Declaring Interfaces Implementing Multiple Interfaces Virtual Implementing Interface Methods .NET Build-IN Interfaces.
E N D
Agenda • Declaring Interfaces • Implementing Multiple Interfaces • Virtual Implementing Interface Methods • .NET Build-IN Interfaces
Agenda • Declaring Interfaces • Implementing Multiple Interfaces • Virtual Implementing Interface Methods • .NET Build-IN Interfaces
Declaring Interfaces • בשפת C# מחלקה יכולה לרשת מחלקה אחת בלבד, אולם בנוסף היא יכולה לרשת מספר רב של ממשקים. • ממשק (Interface) הנו מבנה לוגי המצהיר על מתודות מופשטות (Abstract Methods), מאפיינים מופשטים או אירועים (Events). • ממשק אינו יכול להכיל מתודות עם מימושים או Data Members. • ממשק דומה למחלקה אבסטרקטית (Abstract class) בזה שלא ניתן לייצר ממנו מופעים. • אולם הוא שונה ממחלקה אבסטרקטית משום שהוא יכול להגדיר רק חברים מופשטים. • בממשקים לא ניתן להגדיר הרשאות גישה הם תמיד public, • המימושים במחלקות הנגזרות לא חייבים להיות וירטואליים.
Declaring Interfaces Syntax: interface ISample { void Method1(); float Method2(); object Method3(); . . . string MethodN(); int Property1 { set; get; } event DelegateName EventName; } מקובל ששם ממשק מתחיל באות 'I '
Declaring Interfaces לדוגמה: interface IPrint { void Print(); byte Num { get; } }
Declaring Interfaces לדוגמה: class Sample : IPrint { privatebyte m_Num; public Sample() { … } public Sample(byte num) { this.m_Num = num; } publicvoid Print() { . . . } publicbyte Num { get { return m_Num; } } } • מחלקה היורשת ממשק חייבת לממש את כל המתודות והמאפיינים שהממשק מגדיר, המימוש יכול להיות וירטואלי, אולם הוא לא חייב להיות כזה. • מקובל לאמר שמחלקה "מממשת" ממשק.
Declaring Interfaces לדוגמה: class App { staticvoid Main(string[] args) { Sample s = new Sample(123); s.Print(); IPrint p = new Sample(45); p.Print(); } }
Declaring Interfaces מדוע ממשקים - "הורשה מרובה" : #C אינה תומכת בהורשה מרובה (Multiple Inheritance) . לדוגמה: מה התחליף?
Declaring Interfaces מדוע ממשקים - "הורשה מרובה" : התחליף ש- #C מציעה הוא ממשקים. לדוגמה:
Declaring Interfaces מדוע ממשקים - "הורשה מרובה" : התחליף ש- #C מציעה הוא ממשקים. לדוגמה: כל כלי תחבורה שמציג נהיגת אקסטרים, יממש את הממשק IExtremeDriving כל כלי תחבורה שמסוגל לבצע עבודות חקלאיות יממש את הממשק IAgriculturalJobs
Declaring Interfaces מדוע ממשקים – "חוזה": נניח שאנו מפתחים תוכנה לניהול מפעל לייצור רהיטים, התוכנה מסוגלת לקלוט פרטי הזמנת רהיט, לחלק אותה למרכיביה השונים (הפלטות), ולשלוח הוראות ייצור למכונות הייצור האוטומטיות השונות (CNC). בתהליך הייצור משתתפות מספר מכונות שלכל מכונה יש תפקיד מוגדר, לדוגמה: מכונת חיתוך פלטות, מכונת קידוח, מכונת קנטים, כרסומת וכו. מענייננו לקבוע את ההתנהגויות הנדרשות מכל מכונה, אולם, אין אנו מתעניינים בדרך בה המכונה תבצע את המטלה. למעשה ניתן להגדיר שמכל המכונות אנו דורשים את ההתנהגויות שלהלן: LoadBluePrint, TranslateBluePrint, StartProcess. כל המכונות האוטומטיות אמורות לקבל הוראות מהתוכנה לניהול מפעל לייצור רהיטים.
Declaring Interfaces מדוע ממשקים – "חוזה": ניתן לומר שאנו צריכים להגדיר "חוזה" בין התוכנה לבין המכונות. המכונות אמורות לממש את ההתנהגויות שהתוכנה דורשת מהן, כל מכונה תממש את ההתנהגות בצורה המתאימה לה. לדוגמה: כאשר תינתן הפקודה StartProcess המשור יחתוך את הפלטות על פי המידות שהגדירה התוכנה, מכונת הקידוח תקדח חורים במידות ובמקומות שהגדירה התוכנה, מכונת הקנטים תדביק קנטים בגוון, ובעובי המתאים לפלטה וכו' המכונות אמורות, בנוסף, לספק שיטה שתאפשר לתוכנה לתקשר איתן.
Declaring Interfaces מדוע ממשקים – "חוזה": לצורך כך #C מגדירה ממשקים:
Declaring Interfaces מדוע ממשקים – "חוזה": public interface ICncMachine { void LoadBluePrint(); void TranslateBluePrint(); void StartProcess(); }
Declaring Interfaces מדוע ממשקים – "חוזה": public class SawMachine : ICncMachine { public void LoadBluePrint() { . . . } public void TranslateBluePrint() { . . . } public void StartProcess() { . . . } }
Declaring Interfaces מדוע ממשקים – "חוזה": public class Rotter : ICncMachine { public void LoadBluePrint() { . . . } public void TranslateBluePrint() { . . . } public void StartProcess() { . . . } }
Declaring Interfaces מדוע ממשקים – "חוזה": public class DrillMachine : ICncMachine { public void LoadBluePrint() { . . . } public void TranslateBluePrint() { . . . } public void StartProcess() { . . . } }
Declaring Interfaces מדוע ממשקים – "חוזה": public class CarpentryWorkshop { private ICncMachine[] machines = new ICncMachine[100]; private int counter; public void AddMachine(ICncMachine new_machine) { machines[counter++] = new_machine; } public void CreateFurniture() { for(int i=0;i<counter;i++) { machines[i].LoadBluePrint(); machines[i].TranslateBluePrint(); machines[i].StartProcess(); } } }
Declaring Interfaces מדוע ממשקים – "חוזה":Main public class App { public static void Main() { CarpentryWorkshop carpentry = new CarpentryWorkshop(); carpentry.AddMachine(new SawMachine()); carpentry.AddMachine(new DrillMachine()); carpentry.AddMachine(new Rotter()); carpentry.CreateFurniture(); } }
Declaring Interfaces Declaring Interfaces מדוע ממשקים – "חוזה": בעל המפעל יחליט להוסיף למערך הייצור מכונת אריזה חדשה: public class PackingMachine : ICncMachine { public void LoadBluePrint() {. . .} public void TranslateBluePrint(){ . . .} public void StartProcess(){. . .} }
Declaring Interfaces מדוע ממשקים – "חוזה": פלט
Agenda • Declaring Interfaces • Implementing Multiple Interfaces • Virtual Implementing Interface Methods • .NET Build-IN Interfaces
Implementing Multiple Interfaces מחלקה יכולה לרשת רק מחלקה אחת בלבד, אולם בנוסף (או במקום) היא יכולה לרשת ממשקים רבים. המחלקה היורשת חייבת כמובן לממש את כל המתודות והמאפיינים של כל הממשקים אותם היא יורשת. לדוגמה: publicinterface IPrint { void Print(); } publicinterface IMath { int Sum(); float Avg();. }
Implementing Multiple Interfaces המשך: class Sample : IPrint , IMath { . . . public Sample() { ... } public Sample(byte n1,byte n2,byte n3) { ... } publicvoid Print() { . . . } publicint Sum() { return m_Num1+m_Num2+m_Num3; } publicfloat Avg() { return (float)Sum()/3; } }
Implementing Multiple Interfaces ממשק בעצמו יכול לרשת ממשק אחד או יותר. לדוגמה:
Implementing Multiple Interfaces ממשק בעצמו יכול לרשת ממשק אחד או יותר. לדוגמה: public interface IBaseReport { void CreateReport(); void WriteReport(); void ReadReport(); } public interface ICustomersReport:IBaseReport { void ReportByMonth(); void ReportByProduct(); void ReportByPrGroup(); }
Implementing Multiple Interfaces מחלקה המממשת ממשק נגזר, חייבת לממש את כל מה שמוגדר הן בממשק הבסיס והן בממשק הנגזר. לדוגמה:
Implementing Multiple Interfaces מחלקה המממשת ממשק נגזר, חייבת לממש את כל מה שמוגדר הן בממשק הבסיס והן בממשק הנגזר. לדוגמה: public class Customer : Person,ICustomersReport { private int CustomerID; private object Purchases; public void ReportByMonth() {. . .} public void ReportByProduct() {. . .} public void ReportByPrGroup() {. . .} public void CreateReport() {. . .} public void WriteReport() {. . .} public void ReadReport() {. . .} }
Implementing Multiple Interfaces Explicitly Implementing Interface Methods לעיתים קורה שמחלקה יורשת שני ממשקים שונים, אולם שניהם מכילים הגדרה זהה של מתודה? במקרה שכזה נהיה חייבים לממש את המתודות של הממשקים באופן מפורש (Explicit). המגבלות הקיימות במקרה זה הנם: • לא ניתן להגדיר הרשאת גישה באופן משתמע, הרשאת הגישה היא תמיד public ובאופן מרומז. • מימוש מפורש אינו יכול להיות וירטואלי.
Implementing Multiple Interfaces Explicitly Implementing Interface Methods לדוגמה: publicinterface IPrint1 { void Print(); } publicinterface IPrint2 { void Print(); } class Sample:IPrint1,IPrint2 { public Sample() { ... } public Sample(int num) { ... } void IPrint1.Print() { ... } void IPrint2.Print() { ... } }
Implementing Multiple Interfaces Explicitly Implementing Interface Methods קריאה לאחת מהמתודות מחייבת שימוש ב- Casting . לדוגמה: class Application { staticvoid Main(string[] args) { Sample s = new Sample(33); ((IPrint1)s).Print(); ((IPrint2)s).Print(); IPrint1 i1 = new Sample(12); i1.Print(); IPrint2 i2 = new Sample(45); i1.Print(); } }
Implementing Multiple Interfaces Explicitly Implementing Interface Methods סביר להניח שבממשקים אשר מתוכננים על ידינו לא יווצר מצב לא בריא שכזה. אולם, מצב זה, של שני ממשקים או יותר המגדירים מתודה בעלת חתימה זהה אפשרי כאשר ניעזר בשירותים חיצוניים, או כאשר נשלב בתוכנית רכיבים (Components) אשר נכתבו על ידי גורמים אחרים (Third Party).
Agenda • Declaring Interfaces • Implementing Multiple Interfaces • Virtual Implementing Interface Methods • .NET Build-IN Interfaces
Virtual Implementing מחלקה המממשת ממשק יכולה חייבת לממש את המתודות הוירטואליות המוגדרות בה. המימוש יכול להיות מימוש וירטואלי, כך שמחלקה נגזרת תוכל לדרוס את המימוש של מחלקת הבסיס.
Virtual Implementing Virtual Implementing לדוגמה: public interface IReports { void HtmlReport(); void XmlReport(); }
Virtual Implementing Virtual Implementing המשך: public class Base : IReports { public virtual void HtmlReport() { Console.WriteLine("Base class : Generate Html Report"); } public virtual void XmlReport() { Console.WriteLine("Base class : Generate XML Report"); } }
Virtual Implementing Virtual Implementing המשך: public class Derived : Base, IReports { public override void HtmlReport() { Console.WriteLine("Derived class : Generate Html Report"); } public override void XmlReport() { Console.WriteLine("Derived class : Generate XML Report"); } }
Agenda • Declaring Interfaces • Implementing Multiple Interfaces • Virtual Implementing Interface Methods • .NET Build-IN Interfaces
.NET Build-IN Interfaces סביבת .NET Framework מגדירה אוסף גדול של ממשקים, חלק גדול מהמחלקות של .NET Framework מממש את אותן הממשקים, או מצפה מאיתנו לממש ממשקים אלו על מנת שנוכל ליהנות משירותים שונים שאותן מחלקות מציעות. IComparrer IComparable IFormattable IConvertible IWin32Window IDataAdapter ISerializable IWebProxy IDisposable
.NET Build-IN Interfaces IComparable הממשק IComparable מגדיר מתודה אחת: int CompareTo(Object); ייעודה של המתודה לבצע השוואה בין שני אובייקטים מאותו הטיפוס, או מטיפוסים שונים בעלי מחלקת בסיס משותפת. מתי ננצל ממשק זה ? כאשר נרצה למיין אוסף של אובייקטים על פי קריטריון מסוים. .NET Framework מגדירה מחלקה בשם System.Array , כל המערכים בסביבת פיתוח זו יורשים את המחלקה System.Array . מחלקה זו מגדירה מתודה Static הנקראת Array.Sort(Array obj). מתודה זו יודעת למיין (מממשת את אלגוריתם qsort) כל מערך של טיפוסים אשר ירשו ויממשו את המתודה IComparable.CompareTo(object).
.NET Build-IN Interfaces IComparable לדוגמה : הטיפוס System.Int32 מממש בין השאר גם את הממשק IComparable: public struct Int32 : IComparable, IFormattable, IConvertible וכמובן מממש את המתודה CompareTo(Object obj) . כמוהו כל הטיפוסים הפשוטים (byte, short , ushort. Float , long, ulong וכו'). המתודה Array.Sort(Array) יודעת למיין את כל הטיפוסים הפרימיטיביים המוגדרים ב- .NET Framework. Array.Sort(Array) מממשת את האלגוריתם QSort, כאשר האלגוריתם זקוק להשוואה הוא קורא למתודה CompareTo.
.NET Build-IN Interfaces IComparable אולם מה יקרה אם נרצה למיין באמצעותה מערך אובייקטים ממחלקה אשר אנו הגדרנו , UDT ? כדי שנוכל לבצע זאת נגזור את הממשק IComparable ונממש את המתודה CompareTo בהתאם לצרכינו. ניתן לראות פעולה זאת כ"חוזה" בין מחלקות אשר אין ביניהן שום קשר היררכי. על פי תנאי "החוזה" המתודה Array.Sort תהיה מסוגלת למיין כל סוג של טיפוס , בתנאי שהוא יממש את IComparable ויספק למתודה Array.Sort את המימוש של המתודה CompareTo אשר המתודה Array.Sort עושה בו שימוש כאשר היא זקוקה להשוואות בין האובייקטים השונים במערך.
.NET Build-IN Interfaces IComparable דוגמה: publicclass Circle : IComparable { . . . // IComparable implementation publicint CompareTo(object obj) { Circle c = null; if(obj is Circle) c = (Circle)obj; else return 1; returnthis.m_Radius - c.m_Radius; } }
.NET Build-IN Interfaces IComparable המשך : class App { staticvoid Main(string[] args) { Random rnd = new Random(); Circle[] arr = new Circle[10]; for(int i=0;i<10;i++) arr[i] = new Circle(rnd.Next(200), rnd.Next(200), rnd.Next(50)); Console.WriteLine("Unsorted array."); foreach (Circle c in arr) Console.WriteLine(c.CalcArea()); Array.Sort(arr); Console.WriteLine("Sorted Array."); foreach (Circle c in arr) Console.WriteLine(c.CalcArea()); } }
.NET Build-IN Interfaces IDisposable הממשק IDisposable מגדיר מתודה אחת ויחידה: void DIspose(); בגלל צורת העבודה של ה- GC לא ניתן לדעת מראש מתי הוא יפעל, ואילו אובייקטים הוא יהרוס. לעיתים אובייקט מכיל משאבים לא מנוהלים כגון : Handles , Files , Streams . רצוי להרוס את אותם משאבים מיד כאשר ההאובייקט אינו נחוץ עוד. הממשק IDisposable עוזר לנו במשימה זו.
.NET Build-IN Interfaces IDisposable מחלקה המכילה משאבים לא מנוהלים תממש את הממשק IDisposable . לדוגמה: public class Sample : IDisposable { public Sample(){ ... } ~Sample() { ... } public void DoSomething() { ... } public void Dispose() { Console.WriteLine( "Calling the Dispose Method..." ); Console.WriteLine( "Erasing Resources ..." ); GC.SuppressFinalize(this); } }
.NET Build-IN Interfaces IDisposable הפעלת המתודה Dispose מתבצעת בצורה ישירה או עקיפה. צורה ישירה : public class SampleMain { static public void Main() { Sample t = new Sample(); t.DoSomething(); t.Dispose(); } }
.NET Build-IN Interfaces IDisposable הפעלת המתודה Dispose מתבצעת בצורה ישירה או עקיפה. צורה עקיפה : public class SampleMain { static public void Main() { using (Sample t = new Sample() ) { t. DoSomething(); } } } משפט using מגדיר בלוק , ביציאה מהבלוק תופעל המתודה Dispose .
Agenda • Declaring Interfaces • Implementing Multiple Interfaces • Virtual Implementing Interface Methods • .NET Build-IN Interfaces