1.59k likes | 1.73k Views
繼承與多型 (Inheritance and Polymorphism). 鄭士康 國立台灣大學 電機工程學系 / 電信工程研究所 / 資訊網路與多媒體研究所. 綱要. 繼承 修飾語 protected 限制繼承 繼承架構下的建構函式呼叫 OCP: 開放 - 封閉原理 多型 覆寫與隱藏 二十一點模擬程式 0.1 版. 綱要. 預設類別 System.Object LSP: Liskov 替代性原理 抽象類別 DIP: 依存性反轉原理 介面 ISP: 介面分離原理 多重介面 *多重介面鑄形. 綱要. 繼承 修飾語 protected
E N D
繼承與多型(Inheritance and Polymorphism) 鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
綱要 • 繼承 • 修飾語protected • 限制繼承 • 繼承架構下的建構函式呼叫 • OCP:開放-封閉原理 • 多型 • 覆寫與隱藏 • 二十一點模擬程式0.1版
綱要 • 預設類別System.Object • LSP: Liskov替代性原理 • 抽象類別 • DIP: 依存性反轉原理 • 介面 • ISP: 介面分離原理 • 多重介面 • *多重介面鑄形
綱要 • 繼承 • 修飾語protected • 限制繼承 • 繼承架構下的建構函式呼叫 • OCP:開放-封閉原理 • 多型 • 覆寫與隱藏 • 二十一點模擬程式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.Main 片段(1/2) switch (op) { case ‘+’: result = AdvancedCalculator.Add(operand1,operand2); Console.WriteLine("{0} + {1} = {2} ", operand1, operand2, result); break; . . .
UsingInheritance.Program.Main 片段(2/2) case ‘^’: result = AdvancedCalculator.Power(operand1, operand2); Console.WriteLine(" {0} ^ {1} = {2}", operand1, operand2, result); break; . . . }
UsingInheritance.AdvancedCalculator 片段 class AdvancedCalculator : Calculator { public static int Power(int a, int b) { int result = (int)Math.Pow(a, b); return result; } }
A B C 類別繼承之階層關係 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(); data1 a data2 c data1 data1 b data2 data2 data3 data3 data1 data4
DataMemberInheritance.A class A{ private int data1; private int data2; public A(){ data1 = 1; data2 = 2; } public void GetAData(out int data1, out int data2){ data1 = this.data1; data2 = this.data2; } }
DataMemberInheritance.B class B : A{ private int data3; public B(){ data3 = 3; } public void GetBData(out int data3){ data3 = this.data3; } }
DataMemberInheritance.C class C : B{ private int data1; private int data4; public C(){ data1 = 5; data4 = 4; } public void GetCData(out int data1, out int data4){ data1 = this.data1; data4 = this.data4; } }
DataMemberInheritance.Program.Main 片段 (1/2) A a = new A(); B b = new B(); C c = new C(); a.GetAData(out data1, out data2); Debug.Assert(data1 == 1 && data2 == 2); b.GetAData(out data1, out data2); Debug.Assert(data1 == 1 && data2 == 2); b.GetBData(out data3); Debug.Assert(data3 == 3); c.GetAData(out data1, out data2); Debug.Assert(data1 == 1 && data2 == 2);
DataMemberInheritance.Program.Main 片段 (2/2) c.GetBData(out data3); Debug.Assert(data3 == 3); c.GetCData(out data1, out data4); Debug.Assert(data1 == 5 && data4 == 4);
MemberFunctionInheritance.A class A{ private int data1; private int data2; public A(){ data1 = 1; data2 = 2; } public int GetData1(){ return data1; } public int GetData2(){ return data2; } }
MemberFunctionInheritance.B class B : A{ private int data3; public B(){ data3 = 3; } public int Data3{ get { return data3; } } public int GetSum() { return (GetData2() + data3); } }
MemberFunctionInheritance.C (1/2) class C : B{ private int data1; private int data4; public C(){ data1 = 5; data4 = 4; } public new int GetData1(){ return data1; }
MemberFunctionInheritance.C (2/2) public int GetData4(){ return data4; } public int GetAData1() { return base.GetData1(); } }
MemberFunctionInheritance.Program.Main片段 (1/2) A a = new A(); B b = new B(); C c = new C(); data1 = a.GetData1(); data2 = a.GetData2(); Debug.Assert(data1 == 1 && data2 == 2); data1 = b.GetData1(); data2 = b.GetData2(); data3 = b.Data3; Debug.Assert(data1 == 1 && data2 == 2 && data3 == 3);
MemberFunctionInheritance.Program.Main片段 (2/2) int sum = b.GetSum(); Debug.Assert(sum == 5); data1 = c.GetData1(); data2 = c.GetData2(); data3 = c.Data3; data4 = c.GetData4(); int aAData1 = c.GetAData1(); Debug.Assert(data1 == 5 && data2 == 2 && data3 == 3 && data4 == 4 && aAData1 == 1);
練習 • 實作並測試下列繼承關係
綱要 • 繼承 • 修飾語protected • 限制繼承 • 繼承架構下的建構函式呼叫 • OCP:開放-封閉原理 • 多型 • 覆寫與隱藏 • 二十一點模擬程式0.1版
CalculatorInheritance.Program.Main片段 Calculator c = new Calculator(); c.Run(); AdvancedCalculator ac = new AdvancedCalculator(); ac.Run();
CalculatorInheritance.Calculator片段 protected int register1; protected int register2; protected int display; protected char op; public Calculator(){ register1 = 0; register2 = 0; display = 0; op = '+'; }
CalculatorInheritance.Calculator.Run片段 (1/2) Console.WriteLine("Calculator"); while(true){ Console.Write("Turning off? (Y/N): "); answer = char.Parse(Console.ReadLine()); if( answer == 'Y' || answer == 'y' ) break; Console.Write("Enter operand 1: "); register1 = int.Parse(Console.ReadLine()); Console.Write( "Enter operator +, -, *, /"); op = char.Parse(Console.ReadLine()); Console.Write("Enter operand 2: "); register2 = int.Parse(Console.ReadLine());
CalculatorInheritance.Calculator.Run片段 (2/2) switch (op){ case '+': Add(); break; case '-': Subtract(); break; . . . . . . default: Console.WriteLine( "Should not see this message. Debug!!!"); break; } Console.WriteLine(display); }
CalculatorInheritance.Calculator片段 protected void Add(){ display = register1 + register2; } protected void Subtract(){ display = register1 - register2; } protected void Multiply(){ display = register1 * register2; } protected void Divide(){ display = register1 / register2; }
CalculatorInheritance.AdvancedCalculator (1/3) class AdvancedCalculator : Calculator{ public new void Run(){ Console.WriteLine("Advanced Calculator"); while(true){ Console.Write("Turning off? (Y/N): "); answer = char.Parse(Console.ReadLine()); if( answer == 'Y' || answer == 'y' ) break; Console.Write("Enter operand 1: "); register1=int.Parse(Console.ReadLine()); Console.Write( "Enter operator +, -, *, /, ^ "); op = char.Parse(Console.ReadLine());
CalculatorInheritance.AdvancedCalculator (2/3) Console.Write("Enter operand 2:"); register2=int.Parse(Console.ReadLine()); switch (op){ . . . . . . case '^': Power(); break; default: . . . . . . } Console.WriteLine(display); } }
CalculatorInheritance.AdvancedCalculator (3/3) protected void Power(){ display = (int) Math.Pow(register1, register2); } }
綱要 • 繼承 • 修飾語protected • 限制繼承 • 繼承架構下的建構函式呼叫 • OCP:開放-封閉原理 • 多型 • 覆寫與隱藏 • 二十一點模擬程式0.1版
SealedClassExample.Parent sealed class Parent{ private int data1; public Parent(){ data1 = 0; } public int Data1{ get { return data1; } } }
SealedClassExample.Child class Child : Parent // Error! { private int data2; public Child(){ data2 = 0; } public int Data2{ get { return data2; } } }
綱要 • 繼承 • 修飾語protected • 限制繼承 • 繼承架構下的建構函式呼叫 • OCP:開放-封閉原理 • 多型 • 覆寫與隱藏 • 二十一點模擬程式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.Animal class Animal { private string species; public Animal() { Console.WriteLine("Animal()"); species = "Animal"; } public Animal( string s ) { Console.WriteLine("Animal("+ s +")"); species = s; } }
UsingConstructorsForInheritanc.Primate class Primate : Animal { private int heartCham; public Primate() : base() { Console.WriteLine( "Primate()" ); } public Primate( int n ) : base( "Primate" ) { Console.WriteLine("Primate(" + n +")"); heartCham = n; } }
UsingConstructorsForInheritanc.Human 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
綱要 • 繼承 • 修飾語protected • 限制繼承 • 繼承架構下的建構函式呼叫 • OCP:開放-封閉原理 • 多型 • 覆寫與隱藏 • 二十一點模擬程式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.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.DrawAllShapes 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.DrawCircle及DrawRectangle static void DrawCircle(Circle c) { Console.WriteLine("Draw a circle"); } static void DrawRectangle(Rectangle r) { Console.WriteLine("Draw a rectangle"); }
OCPViolationExample 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; } }