Transcript
  • (Inheritance and Polymorphism)//

  • protectedOCP:-0.1*

  • System.ObjectLSP: LiskovDIP: ISP: *

  • protectedOCP:-0.1

  • UsingInheritance.Calculator public int Add(int a, int b) { int result = a + b; return result;}public int Subtract(int a, int b){ int result = a - b; return result;}public int Multiply(int a, int b){ int result = a * b; return result;}

  • UsingInheritance.Program.Program.Main() (1/2)AdvancedCalculator calculator = new AdvancedCalculator();. . . switch (op){case 1: result = calculator.Add(operand1,operand2); Console.WriteLine("{0} + {1} = {2} ", operand1, operand2, result); break;. . .

  • UsingInheritance.Program.Program.Main() (2/2)case 5: functionValue = calculator.GetSine(angle); Console.WriteLine( "Sine of {0} (deg) = {1}", angle, functionValue); break;. . .}

  • UsingInheritance.AdvancedCalculator public class AdvancedCalculator : Calculator{ public double GetSine(double angle) { angle *= Math.PI / 180.0; return Math.Sin(angle); } . . .}

  • UML

  • class A {private int data1;private int data2; //other members are methods}

    class B : A {private int data3; //other members are methods}

    class C : B {private int data1;private int data4; //other members are methods}

  • A a = new A();B b = new B();C c = new C();data1data2data1data2data3abdata1data2data3data1data4c

  • protectedOCP:-0.1

  • UsingProtected.Program.Program.Main()DC d = new DC();d.SetX(3);//Console.WriteLine( d.GetX() ) ; // Error!//d.x = 77; // Error!d.Add2();

  • UsingProtected.Programclass BC { private int x; public void SetX( int x ) { this.x = x; } protected int GetX() { return x; }}class DC : BC { public void Add2() { int c = GetX(); SetX( c+2 ); } }

  • protectedOCP:-0.1

  • sealed class SClass {. . . . . .}

  • protectedOCP:-0.1

  • UsingConstructorsForInheritance.Program.Main() Animal slug = new Animal();Animal tweety = new Animal( "canary" );Primate godzilla = new Primate();Primate human = new Primate( 4 );Human jill = new Human();

  • UsingConstructorsForInheritance.Program (1/3)class Animal { private string species; public Animal() { Console.WriteLine("Animal()"); species = "Animal";}public Animal( string s ) { Console.WriteLine("Animal("+ s +")"); species = s; }}

  • UsingConstructorsForInheritance.Program(2/3)class Primate : Animal { private int heartCham; public Primate() : base() { Console.WriteLine( "Primate()" );}public Primate( int n ) : base( "Primate" ) { Console.WriteLine("Primate(" + n +")"); heartCham = n;}}

  • UsingConstructorsForInheritance.Program (3/3)class Human : Primate { public Human() : base( 4 ) { Console.WriteLine( "Human()" );}}

  • Primate human = new Primate( 4 );public Primate( int n ) : base( "Primate" ){ . . .

    }public Animal( string s ){ . . . }

  • UsingConstructorsForInheritance

  • protectedOCP:-0.1

  • -(OCP:Open-Closed Principle)Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification*Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003

  • OCPViolationExample

  • OCPViolationExample.Program.Program.Main() Point center;center.x = 15;center.y = 20;Point topLeft;topLeft.x = 30;topLeft.y = 40;Shape[] list = { new Circle(2, center), new Rectangle(3, 4, topLeft) };DrawAllShapes(list);

  • OCPViolationExample.Program.Program (1/2)static void DrawAllShapes(Shape[] list) { for (int i = 0; i < list.Length; ++i) { Shape s = list[i]; switch (s.type) { case ShapeType.CIRCLE: DrawCircle((Circle) s); break; case ShapeType.RECTANGLE: DrawRectangle((Rectangle) s); break; } }}

  • OCPViolationExample.Program.Program (2/2)static void DrawCircle(Circle c){ Console.WriteLine("Draw a circle");}static void DrawRectangle(Rectangle r){ Console.WriteLine("Draw a rectangle");}

  • OCPViolationExample.Program (1/2)class Shape { public ShapeType type; public Shape(ShapeType t) { type = t; }}class Circle : Shape { private int radius; private Point center; public Circle(int radius, Point center) :base(ShapeType.CIRCLE) { this.radius = radius; this.center = center; }}

  • OCPViolationExample.Program (2/2)class Rectangle : Shape{ private int width; private int height; private Point topLeft; public Rectangle(int width, int height, Point topLeft) : base(ShapeType.RECTANGLE) { this.width = width; this.height = height; this.topLeft = topLeft; }}

  • OCPViolationExampleShape()switchShapeenumswitchProgramDraw

  • protectedOCP:-0.1

  • (packaging)(inheritance)(polymorphism)

  • (compile-time binding)(run-time binding)(static binding)(dynamic binding)(virtual)(override)

  • DrawingAllShapes

  • DrawingAllShapes.Program.Program.Main() (1/2)Shape[] list = new Shape[2];Point center;center.x = 15;center.y = 20;Point topLeft;topLeft.x = 30;topLeft.y = 40;Circle c = new Circle(2, center);Rectangle r = new Rectangle(3, 4, topLeft);Console.WriteLine(", ");Console.WriteLine("1: , ");Console.WriteLine("2: , ");int ans = int.Parse(Console.ReadLine());

  • DrawingAllShapes.Program.Program.Main() (2/2)switch (ans){ case 1: list[0] = c; list[1] = r; break; case 2: list[0] = r; list[1] = c; break; default: . . .}DrawAllShapes(list);

  • DrawingAllShapes.Program.Program static void DrawAllShapes(Shape[] list){ int i; for (i = 0; i < list.Length; ++i) { list[i].Draw(); }}

  • DrawingAllShapes.Program (1/3)class Shape{ public Shape() { } virtual public void Draw() { }}

  • DrawingAllShapes.Program (2/3)class Circle : Shape{ private int radius; private Point center; public Circle(int radius, Point center) { this.radius = radius; this.center = center; } override public void Draw() { Console.WriteLine("Draw a circle"); }}

  • DrawingAllShapes.Program (3/3)class Rectangle : Shape { private int width; private int height; private Point topLeft; public Rectangle(int width, int height, Point topLeft) { this.width = width; this.height = height; this.topLeft = topLeft; } override public void Draw() { Console.WriteLine("Draw a rectangle"); }}

  • DrawingAllShapesTriangle

  • protectedOCP:-0.1

  • BlackJack_0_1

  • BlackJack_0_1.BlackJackTest (1/2)public static bool Scenario1_OK(){ Card[] cards = { new Card(Suit.SPADE, 1), new Card(Suit.HEART, 11), new Card(Suit.DIAMOND, 10) }; Deck deck = new Deck(cards); Player player = new Player(); Dealer dealer = new Dealer();

  • BlackJack_0_1.BlackJackTest (2/2)player.SaveACard(deck.DealACard()); dealer.SaveACard(deck.DealACard()); player.SaveACard(deck.DealACard()); return( player.GetStatus() == Status.BLACK_JACK && dealer.GetStatus() == Status.PASS);}

  • BlackJack_0_1.Game (1/6)const int N_PLAYERS = 2;Deck deck;Player[] players = new Player[N_PLAYERS];public Game(){ players[0] = new Player("Jeng"); players[N_PLAYERS-1] = new Dealer();}

  • BlackJack_0_1.Game (2/6)private void Play() { int i; // for (i = 0; i < N_PLAYERS; ++i) { players[i].SaveACard( deck.DealACard()); players[i].Dump(); }

  • BlackJack_0_1.Game (3/6) // for (i=0; i < N_PLAYERS; ++i) { players[i].SaveACard( deck.DealACard()); players[i].Dump(); }

  • BlackJack_0_1.Game (4/6) // for(i=0; i
  • BlackJack_0_1.Game (5/6) // Player dealer = players[N_PLAYERS-1]; for(i=0; i= players[i].GetTotalPoints()) { Console.WriteLine( dealer.Name + ""+players[i].Name); } else { Console.WriteLine( players[i].Name+""+dealer.Name); } }}

  • BlackJack_0_1.Game (6/6)private bool IsBlackJackOrBurst( Player player) { bool isBlackJack = false; if (player.GetStatus()==Status.BLACK_JACK) { isBlackJack = true; Console.WriteLine(player.Name+ " BlackJack!!!"); } bool isBurst = false; if (player.GetStatus() == Status.BURST){ isBurst = true; Console.WriteLine(player.Name+" !!!"); } return (isBlackJack || isBurst); }

  • BlackJack_0_1.Player (1/5)private Card[] hand = new Card[11];private int nCards;private Status status;private int totalPoints;private string name;public Player(){ nCards = 0; name = "";}

  • BlackJack_0_1.Player (2/5)public Player(string name){ nCards = 0; this.name = name;}public string Name{ get { return name; }}

  • BlackJack_0_1.Player (3/5)virtual public bool WantOneMoreCard(){ Console.Write("? (y/n) "); string answer = Console.ReadLine(); return (answer == "Y" || answer == "y");}

  • BlackJack_0_1.Player (4/5)public void Dump(){ int i; Console.Write(name+" : "); for (i = 0; i < nCards; ++i) { hand[i].Dump(); Console.Write("\t"); if ((i + 1) % 5 == 0) Console.WriteLine(); }

  • BlackJack_0_1.Player (5/5) Console.WriteLine(); Console.WriteLine(name + " : " + totalPoints);}

  • BlackJack_0_1.Dealerclass Dealer : Player { public Dealer() : base("") {} override public bool WantOneMoreCard() { return (base.GetTotalPoints() < 17); }}

  • protectedOCP:-0.1

  • UsingBase.Program

  • UsingBase.Program (1/3)// Define the base classclass Car{ public virtual void DescribeCar() { System.Console.WriteLine( "Four wheels and an engine."); }}

  • UsingBase.Program (2/3)// Define the derived classesclass ConvertibleCar : Car{ public new virtual void DescribeCar() { base.DescribeCar(); Console.WriteLine("A roof that opens up."); }}

  • UsingBase.Program (3/3)class Minivan : Car{ public override void DescribeCar() { base.DescribeCar(); Console.WriteLine( "Carries seven people."); }}

  • UsingBase.Program.Program.Main() (1/2)// new and override make no differences hereCar car1 = new Car();car1.DescribeCar();Console.WriteLine("----------");

    ConvertibleCar car2 = new ConvertibleCar();car2.DescribeCar();Console.WriteLine("----------");

    Minivan car3 = new Minivan();car3.DescribeCar();Console.WriteLine("----------");

  • UsingBase.Program.Program.Main() (2/2)// they are different in polymorphysm Car[] cars = new Car[3];cars[0] = new Car();cars[1] = new ConvertibleCar();cars[2] = new Minivan();foreach (Car vehicle in cars){ Console.WriteLine("Car object: " + vehicle.GetType()); vehicle.DescribeCar(); Console.WriteLine("----------");}

  • : overridePolymorphism ()

    : new

  • UsingBase

  • System.ObjectLSP: LiskovDIP: ISP: *

  • System.ObjectEqualsGetHashCodeGetTypeReferenceEqualsToStringFinalize

  • InheritingObject.Program.Program.Main()Test t1 = new Test();Test t2 = new Test();bool isEqual = t1.Equals(t2);Console.WriteLine(t1.ToString());Console.WriteLine("t1 t2 " + isEqual);

  • InheritingObject.Program class Test{override public string ToString() { return "InheritingObject.Test"; }}

  • Boxing Unboxingint x = 10;Object obj = (Object) x; // boxingobj = 20;int j = (int)obj; // unboxing

  • System.ObjectLSP: LiskovDIP: ISP: *

  • Liskov (LSP: Liskov Substitution Principle)Subtype must be substitutable for their base typesSo1To2TPPo1o2LSPOCP*Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003

  • IS-A

  • LSPViolationExample.Program (1/4)class Rectangle{ private int width; private int height; virtual public int Width { set { width = value; } } virtual public int Height { set { height = value; } }

  • LSPViolationExample.Program (2/4) public int Area() { return width * height; }}

  • LSPViolationExample.Program (3/4)class Square : Rectangle{ override public int Width { set { base.Width = value; base.Height = value; } } override public int Height { set { base.Width = value; base.Height = value; } }}

  • LSPViolationExample.Program (4/4)class Program{ static void Main(string[] args) { Square s = new Square(); Test(s); } static void Test(Rectangle r) { r.Width = 5; r.Height = 4; Debug.Assert(r.Area() == 20); }}

  • Rectangle.WidthDebug.Assert( (width == value) && (height == old.height));LSP

  • System.ObjectLSP: LiskovDIP: ISP: *

  • AbstractClassExample.Program.Program.Main() double a = 5.0;Square sq = new Square(a);Console.WriteLine("sq" + sq.Area());Circle c = new Circle(a);Console.WriteLine("c" + c.Area());

  • AbstractClassExample.Program (1/3)public abstract class Shape { private string shape; public Shape(string shape) { this.shape = shape; Console.WriteLine("" + shape); } abstract public double Area();}

  • AbstractClassExample.Program (2/3)public class Square : Shape{ double a; public Square(double a): base("") { this.a = a; } public override double Area() { return a * a; }}

  • AbstractClassExample.Program (3/3)public class Circle : Shape{ double r; public Circle(double r): base("") { this.r = r; } public override double Area() { return Math.PI * r * r; }}

  • DrawingAllShapesShapeShape.Draw()

  • System.ObjectLSP: LiskovDIP: ISP: *

  • (DIP: Dependency-Inversion Principle)High-level modules should not depend on low-level modules. Both should depend on abstractions.Abstractions should not depend on details. Details should depend on abstractions.*Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Pearson Education, 2003

  • DIP

  • (State Chart)

  • DIPViolationExample.Program (1/4)public enum LampStatus{ OFF = 0, ON = 1}public enum ButtonStatus{ RELEASED = 0, PRESSED = 1}

  • DIPViolationExample.Program (2/4)public class Lamp { private LampStatus status = LampStatus.OFF; public LampStatus Status { get { return status; } } public void TurnOn() { status = LampStatus.ON; } public void TurnOff() { status = LampStatus.OFF; } }

  • DIPViolationExample.Program (3/4)public class Button{ private ButtonStatus status = ButtonStatus.RELEASED; private Lamp lamp; public Button(Lamp lamp) { this.lamp = lamp; } public ButtonStatus Status { get { return status; } }

  • DIPViolationExample.Program (4/4) public void Press() { if (status == ButtonStatus.RELEASED) { status = ButtonStatus.PRESSED; lamp.TurnOn(); } } public void Release() { if( status == ButtonStatus.PRESSED ){ status = ButtonStatus.RELEASED; lamp.TurnOff(); } }}

  • DIPViolationExample.Program.Program.Main() (1/3)Lamp lamp1 = new Lamp(1);Button button = new Button(lamp1);Random rand = new Random();for (int n = 0; n
  • DIPViolationExample.Program.Program.Main() (2/3) if (rand.Next() % 2 == 1) { if (button.Status == ButtonStatus.PRESSED) { button.Release(); } else { button.Press(); } }

  • DIPViolationExample.Program.Program.Main() (3/3) if (lamp1.Status == LampStatus.OFF) { Console.WriteLine("lamp1 is off"); } else { Console.WriteLine("lamp1 is on"); } Console.WriteLine();}

  • System.ObjectLSP: LiskovDIP: ISP: *

  • UsingInterface.Program.Program.Main() double a = 5.0;Square sq = new Square(a);Console.WriteLine("sq" + sq.Area());Circle c = new Circle(a);Console.WriteLine("c" + c.Area());

  • UsingInterface.Program(1/3)interface Shape{ double Area();}

  • UsingInterface.Program(2/3)public class Square : Shape{ double a; public Square(double a) { this.a = a; } public double Area() { return a * a; }}

  • UsingInterface.Program(3/3)public class Circle : Shape{ double r; public Circle(double r) { this.r = r; } public double Area() { return Math.PI * r * r; }}

  • vs. (1/2)interface Shape{ double Area();}--------------------------------------------public abstract class Shape { private string shape; public Shape(string shape) { this.shape = shape; Console.WriteLine("" + shape); } abstract public double Area();}

  • vs. (2/2)public class Square : Shape {. . . public double Area() { return a * a; }} --------------------------------------------public class Square : Shape { . . . public override double Area() { return a * a; }}

  • DIP

  • ButtonAndLamp.Program (1/4)public interface SwitchableDevice { void TurnOn(); void TurnOff();}public enum LampStatus { OFF = 0, ON = 1}public enum ButtonStatus { RELEASED = 0, PRESSED = 1}

  • ButtonAndLamp.Program (2/4)public class Lamp : SwitchableDevice { private LampStatus status = LampStatus.OFF; public LampStatus Status { get { return status; } } public void TurnOn() { status = LampStatus.ON; } public void TurnOff() { status = LampStatus.OFF; }}

  • ButtonAndLamp.Program (3/4)public class Button{ private ButtonStatus status = ButtonStatus.RELEASED; private SwitchableDevice device; public Button(SwitchableDevice device) { this.device = device; } public ButtonStatus Status { get { return status; } }

  • ButtonAndLamp.Program (4/4) public void Press() { if (status == ButtonStatus.RELEASED) { status = ButtonStatus.PRESSED; device.TurnOn(); } } public void Release() { if (status == ButtonStatus.PRESSED) { status = ButtonStatus.RELEASED; device.TurnOff(); } }}

  • ButtonAndLampFanButtonFan

  • System.ObjectLSP: LiskovDIP: ISP: *

  • (ISP: Interface-Segregation Principle)Clients should not be forced to depend on methods that they do not use

  • ISP

  • ISPViolationExample.Program (1/4)interface TimerClient { void TimeOut();}interface Door : TimerClient { void Lock(); void Unlock(); bool IsOpen();}enum DoorStatus { CLOSED = 0, OPEN = 1}

  • ISPViolationExample.Program (2/4)class Timer { private int t; private int timeout; private TimerClient client; public Timer(int timeout, TimerClient client) { this.timeout = timeout; this.client = client; t = 0; }

  • ISPViolationExample.Program (3/4) public void Advance() { ++t; if (t % timeout == 0) { client.TimeOut(); } }}class TimedDoor : Door{ private DoorStatus status = DoorStatus.CLOSED;

  • ISPViolationExample.Program (4/4) public bool IsOpen() { return (status == DoorStatus.OPEN); } public void Lock() { if (IsOpen()) status = DoorStatus.CLOSED; } public void Unlock() { if (!IsOpen()) status = DoorStatus.OPEN; } public void TimeOut() { Lock(); }}

  • ISPViolationExample.Program.Program.Main() (1/2)TimedDoor tDoor = new TimedDoor();int timeout = 10;Timer timer = new Timer(timeout, tDoor);int n;const int N = 20;tDoor.Unlock();for (n = 0; n
  • ISPViolationExample.Program.Program.Main() (2/2) if (tDoor.IsOpen()) { Console.WriteLine( "n = " + n + "\t tDoor is open"); } else { Console.WriteLine( "n = " + n + "\t tDoor is closed"); } timer.Advance();}

  • System.ObjectLSP: LiskovDIP: ISP: *

  • MultiInterface

  • MultiInterface.Program.Program.Main()Floatplane fp = new Floatplane();fp.Sail();fp.Fly();

  • MultiInterface.Program (1/2)interface Plane{ void Fly();}

    interface Ship{ void Sail();}

  • MultiInterface.Program (2/2)public class Floatplane : Plane, Ship { public Floatplane() { Console.WriteLine(""); } public void Sail() { Console.WriteLine(""); } public void Fly() { Console.WriteLine(""); }}

  • Clock_RadioClockGetTime()RadioPlayMusic()

  • ISP

  • TimedDoorSimulation.Programinterface TimerClient { void TimeOut();}interface Door { void Lock(); void Unlock(); bool IsOpen();}. . .class TimedDoor : Door, TimerClient{ . . .}

  • System.ObjectLSP: LiskovDIP: ISP: *

  • CastMultiInterfaces

  • CastMultiInterfaces.Program.Program.Main()double a = 5.0;Square sq = new Square(a);Rhombus rhomb = sq as Rhombus;Console.WriteLine( "sq"+rhomb.Area() );if( sq is Rectangle ) { Rectangle rec = (Rectangle) sq; Console.WriteLine("sq"+rec.Area() );}

  • CastMultiInterfaces.Program(1/3)interface Rectangle{ double Area();}interface Rhombus{ double Area();}

  • CastMultiInterfaces.Program(2/3)public class Square : Rectangle, Rhombus{ private double a; private double d; public Square(double a) { this.a = a; d = Math.Sqrt(2.0) * a; }

  • CastMultiInterfaces.Program(3/3)double Rectangle.Area() { return a * a; } double Rhombus.Area() { return 0.5 * d * d; }}


Recommended