Tags: , , | Posted by talgiladi on 11/28/2008 7:28 PM | Comments (2)

או בעברית משהו כמו “עיקרון החילופין של ליסקוב”- אחד מהעקרונות של תכנות מונחה אובייקטים, שאומר בעצם:

אם אני יורש ממחלקת אם, ודורס אחת מהמתודות שלה (overide), הלקוח שמשתמש בקוד שלי, צריך להיות מסוגל להמשיך להשתמש בקוד בצורה שקופה, בלי שהעובדה שהעברתי לו את המחלקה היורשת ולא את מחלקת האם, תפגע בהנחות שלו לגבי המתודה.

אני חייב לקיים את החוקיות שקיימת במחלקת האם, כך שכל unit test, כל קריאה לפרופרטי או פונקציה, תמשיך לפעול בצורה זהה מבחינת מי שמשתמש בקוד שלי. כמובן שמה שקורה מאחורי הקלעים יכול להיות שונה, בשביל זה הרי יצרתי מחלקה יורשת, אבל מבחינתו אין שום הבדל.

דוגמה קטנה תסביר בבירור:

יש לי מחלקה שמייצגת מרובע כלשהוא

 public class Rectangle

    {

        public virtual int Width { get; set; }

        public virtual int Height { get; set; }

        public Rectangle() { }

        public Rectangle(int width, int height)

        {

            this.Width = width;

            this.Height = height;

        }

        public virtual int Size

        {

            get

            {

                return this.Height * this.Width;

            }

        }

    }

וגם בניתי עבורה טסט:

  [TestMethod()]

        public void TestSize()

        {

            int expectedWidth = 3;

            int expectedHeight=7;

            Rectangle rectangle = new Rectangle(expectedWidth, expectedHeight);

            Assert.AreEqual(expectedWidth, rectangle.Width);

            Assert.AreEqual(expectedHeight, rectangle.Height);

        }

כעת יצרתי מחלקה נוספת – ריבוע, שהוא בעצם צורה פרטית של מרובע, אלא שהרוחב שווה תמיד לאורך, אז החלטתי לבנות אותו כתת מחלקה

של המרובע שלי:

 public class Square : Rectangle

    {

        public Square() { }

        public Square(int width)

            : base(width, width)

        {

        }

        public override int Size

        {

            get

            {

                return this.Width * this.Width;

            }

        }

    }

אבל בגלל שלריבוע הרוחב והאורך זהים, אני צריך רק ערך תמיד – של רוחב או גובה, אז שיניתי את הקוד כלעיל.

עכשיו הטסט שלי יכשל:

[TestMethod()]

        public void TestSize()

        {

            int expectedWidth = 3;

            int expectedHeight=7;

            Rectangle square = new Square(expectedWidth);

            Assert.AreEqual(expectedWidth, square.Width);

            Assert.AreEqual(expectedHeight, square.Height);//fail

        }

וזה בדיוק מה שהעיקרון אומר – אם היו לי ציפיות כלשהם ממחלקת האם, הן צריכות להמשיך להתקיים בכל מחלקה שיורשת. מבחינתי לא צריך להיות הבדל אם אני עובד עם מרובע או ריבוע.

מה הפיתרון? במקרה שלנו באמת זה לא אפשרי, אז נצטרך לבטל את הירושה וליצור אולי מחלקה שלישית אבסטרקטית שממנה ירשו גם הריבוע

וגם המרובע, כך שאני דורס מתודה אבסטרקטית ואין לאף אחד ציפיות מוקדמות ממנה, ואני אוכל לעשות מה שארצה.

Technorati Tags: ,,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5