inheritance and polymorphism
Download
Skip this Video
Download Presentation
繼承與多型 (Inheritance and Polymorphism)

Loading in 2 Seconds...

play fullscreen
1 / 159

繼承與多型 (Inheritance and Polymorphism) - PowerPoint PPT Presentation


  • 66 Views
  • Uploaded on

繼承與多型 (Inheritance and Polymorphism). 鄭士康 國立台灣大學 電機工程學系 / 電信工程研究所 / 資訊網路與多媒體研究所. 綱要. 繼承 修飾語 protected 限制繼承 繼承架構下的建構函式呼叫 OCP: 開放 - 封閉原理 多型 覆寫與隱藏 二十一點模擬程式 0.1 版. 綱要. 預設類別 System.Object LSP: Liskov 替代性原理 抽象類別 DIP: 依存性反轉原理 介面 ISP: 介面分離原理 多重介面 *多重介面鑄形. 綱要. 繼承 修飾語 protected

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about '繼承與多型 (Inheritance and Polymorphism)' - alfreda-dawson


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
inheritance and polymorphism

繼承與多型(Inheritance and Polymorphism)

鄭士康

國立台灣大學

電機工程學系/電信工程研究所/

資訊網路與多媒體研究所

slide2
綱要
  • 繼承
  • 修飾語protected
  • 限制繼承
  • 繼承架構下的建構函式呼叫
  • OCP:開放-封閉原理
  • 多型
  • 覆寫與隱藏
  • 二十一點模擬程式0.1版
slide3
綱要
  • 預設類別System.Object
  • LSP: Liskov替代性原理
  • 抽象類別
  • DIP: 依存性反轉原理
  • 介面
  • ISP: 介面分離原理
  • 多重介面
  • *多重介面鑄形
slide4
綱要
  • 繼承
  • 修飾語protected
  • 限制繼承
  • 繼承架構下的建構函式呼叫
  • OCP:開放-封閉原理
  • 多型
  • 覆寫與隱藏
  • 二十一點模擬程式0.1版
usinginheritance calculator
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
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
UsingInheritance.Program.Main 片段(2/2)

case ‘^’:

result =

AdvancedCalculator.Power(operand1,operand2);

Console.WriteLine(" {0} ^ {1} = {2}",

operand1, operand2, result);

break;

. . .

}

usinginheritance advancedcalculator
UsingInheritance.AdvancedCalculator 片段

class AdvancedCalculator : Calculator

{

public static int Power(int a, int b)

{

int result = (int)Math.Pow(a, b);

return result;

}

}

slide10
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

}

slide11
物件記憶體分配模型

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
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
DataMemberInheritance.B

class B : A{

private int data3;

public B(){

data3 = 3;

}

public void GetBData(out int data3){

data3 = this.data3;

}

}

datamemberinheritance c
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
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
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
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
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
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
MemberFunctionInheritance.C (2/2)

public int GetData4(){

return data4;

}

public int GetAData1() {

return base.GetData1();

}

}

memberfunctioninheritance program main 1 2
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
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);

slide23
練習
  • 實作並測試下列繼承關係
slide24
綱要
  • 繼承
  • 修飾語protected
  • 限制繼承
  • 繼承架構下的建構函式呼叫
  • OCP:開放-封閉原理
  • 多型
  • 覆寫與隱藏
  • 二十一點模擬程式0.1版
calculatorinheritance program main
CalculatorInheritance.Program.Main片段

Calculator c = new Calculator();

c.Run();

AdvancedCalculator ac = new AdvancedCalculator();

ac.Run();

calculatorinheritance calculator
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
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
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 calculator1
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
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
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
CalculatorInheritance.AdvancedCalculator (3/3)

protected void Power(){

display = (int) Math.Pow(register1,

register2);

}

}

slide34
綱要
  • 繼承
  • 修飾語protected
  • 限制繼承
  • 繼承架構下的建構函式呼叫
  • OCP:開放-封閉原理
  • 多型
  • 覆寫與隱藏
  • 二十一點模擬程式0.1版
sealedclassexample parent
SealedClassExample.Parent

sealed class Parent{

private int data1;

public Parent(){

data1 = 0;

}

public int Data1{

get { return data1; }

}

}

sealedclassexample child
SealedClassExample.Child

class Child : Parent // Error!

{

private int data2;

public Child(){

data2 = 0;

}

public int Data2{

get { return data2; }

}

}

slide37
綱要
  • 繼承
  • 修飾語protected
  • 限制繼承
  • 繼承架構下的建構函式呼叫
  • OCP:開放-封閉原理
  • 多型
  • 覆寫與隱藏
  • 二十一點模擬程式0.1版
usingconstructorsforinheritance program main
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
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
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
UsingConstructorsForInheritanc.Human

class Human : Primate

{

public Human() : base( 4 )

{

Console.WriteLine( "Human()" );

}

}

slide42
衍生物件產生流程

Primate human = new Primate( 4 );

public Primate( int n ) : base( "Primate" )

{

. . .

}

public Animal( string s )

{

. . .

}

slide43
練習
  • 利用偵錯器體驗了解程式UsingConstructorsForInheritance
slide44
綱要
  • 繼承
  • 修飾語protected
  • 限制繼承
  • 繼承架構下的建構函式呼叫
  • OCP:開放-封閉原理
  • 多型
  • 覆寫與隱藏
  • 二十一點模擬程式0.1版
ocp open closed principle
開放-封閉原理(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
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
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
OCPViolationExample.Program.DrawCircle及DrawRectangle

static void DrawCircle(Circle c)

{

Console.WriteLine("Draw a circle");

}

static void DrawRectangle(Rectangle r)

{

Console.WriteLine("Draw a rectangle");

}

ocpviolationexample1
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;

}

}

ocpviolationexample rectangle
OCPViolationExample.Rectangle

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;

}

}

ocpviolationexample2
OCPViolationExample的主要問題
  • 添加任何有關Shape的演算(例如,拖曳、伸縮、移動、刪除)都要重複麻煩的switch敘述
  • 增加一種新的Shape子類別,必須修改enum敘述、各處的switch敘述,並在類別Program增加對應的Draw函式
slide53
綱要
  • 繼承
  • 修飾語protected
  • 限制繼承
  • 繼承架構下的建構函式呼叫
  • OCP:開放-封閉原理
  • 多型
  • 覆寫與隱藏
  • 二十一點模擬程式0.1版
slide54
物件導向的關鍵技術
  • 封裝(packaging)
  • 繼承(inheritance)
  • 多型(polymorphism)
slide55
多型
  • 編譯時連結(compile-time binding)與執行時連結(run-time binding)
    • 靜態連結(static binding)與動態連結(dynamic binding)
  • 多型之要求
    • 繼承階層體系
    • 虛擬(virtual)與覆寫(override)
    • 基礎類別之參考
  • 多型之優缺點
drawingallshapes program main 1 2
DrawingAllShapes.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 main 2 2
DrawingAllShapes.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 drawallshapes
DrawingAllShapes.Program.DrawAllShapes

static void DrawAllShapes(Shape[] list)

{

int i;

for (i = 0; i < list.Length; ++i)

{

list[i].Draw();

}

}

drawingallshapes shape
DrawingAllShapes.Shape

class Shape

{

public Shape() { }

virtual public void Draw() { }

}

drawingallshapes circle
DrawingAllShapes.Circle

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 rectangle
DrawingAllShapes.Rectangle

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");

}

}

drawingallshapes1
DrawingAllShapes記憶配置

堆積記憶區

堆疊記憶區

c

this

Circle.Draw

c.radius

c.center.x

r

c.center.y

this

Rectangle.Draw

r.width

r.height

r.topLeft.x

r.topLeft.y

slide64
練習
  • 在程式DrawingAllShapes增加類別Triangle,使程式也能畫出三角形。
slide65
綱要
  • 繼承
  • 修飾語protected
  • 限制繼承
  • 繼承架構下的建構函式呼叫
  • OCP:開放-封閉原理
  • 多型
  • 覆寫與隱藏
  • 二十一點模擬程式0.1版
newvsoverride car
NewVsOverride.Car

// Define the base class

class Car

{

public virtual void DescribeCar()

{

System.Console.WriteLine(

"Four wheels and an engine.");

}

}

newvsoverride convertiblecar
NewVsOverride.ConvertibleCar

// Define the derived classes

class ConvertibleCar : Car

{

public new virtual void DescribeCar()

{

base.DescribeCar();

Console.WriteLine(

"A roof that opens up.");

}

}

newvsoverride minivan
NewVsOverride.Minivan

class Minivan : Car

{

public override void DescribeCar()

{

base.DescribeCar();

Console.WriteLine(

"Carries seven people.");

}

}

newvsoverride program main 1 2
NewVsOverride.Program.Main片段 (1/2)

// new and override make no differences here

Car car1 = new Car();

car1.DescribeCar();

Console.WriteLine("----------");

ConvertibleCar car2 = new ConvertibleCar();

car2.DescribeCar();

Console.WriteLine("----------");

Minivan car3 = new Minivan();

car3.DescribeCar();

Console.WriteLine("----------");

newvsoverride program main 2 2
NewVsOverride.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("----------");

}

slide72
覆寫與隱藏
  • 覆寫: override
    • 主要用於Polymorphism (多型)
    • 執行時連結
  • 隱藏: new
    • 只是取代基底類別同名之成員變數與方法
    • 仍是編譯時連結
slide73
練習
  • 利用偵錯器體驗了解程式NewVsOverride
slide74
綱要
  • 繼承
  • 修飾語protected
  • 限制繼承
  • 繼承架構下的建構函式呼叫
  • OCP:開放-封閉原理
  • 多型
  • 覆寫與隱藏
  • 二十一點模擬程式0.1版
blackjack 0 1 blackjacktest 1 2
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
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
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
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
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
BlackJack_0_1.Game 片段 (4/6)

// 開始要牌計牌

for(i=0; i

{

while (players[i].GetStatus() ==

Status.PASS &&

players[i].WantOneMoreCard() &&

deck.HasMoreCard())

{

players[i].SaveACard(deck.DealACard());

players[i].Dump();

if(IsBlackJackOrBurst(players[i]))

return;

}

}

blackjack 0 1 game 5 6
BlackJack_0_1.Game 片段 (5/6)

// 計點分勝負

Player dealer = players[N_PLAYERS-1];

for(i=0; i

if (dealer.GetTotalPoints() >=

players[i].GetTotalPoints()){

Console.WriteLine(dealer.Name +

"勝"+players[i].Name);

}else{

Console.WriteLine(

players[i].Name+"勝"+dealer.Name);

}

}

}

blackjack 0 1 game 6 6
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
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
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
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
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
BlackJack_0_1.Player 片段(5/5)

Console.WriteLine();

Console.WriteLine(name + " 總點數: " +

totalPoints);

}

blackjack 0 1 dealer
BlackJack_0_1.Dealer片段

class Dealer : Player{

public Dealer() : base("莊家"){}

override public bool WantOneMoreCard()

{

return (base.GetTotalPoints() < 17);

}

}

slide90
綱要
  • 預設類別System.Object
  • LSP: Liskov替代性原理
  • 抽象類別
  • DIP: 依存性反轉原理
  • 介面
  • ISP: 介面分離原理
  • 多重介面
  • *多重介面鑄形
system object
預設類別System.Object
  • 一致化型別
  • 成員函式
    • Equals
    • GetHashCode
    • GetType
    • ReferenceEquals
    • ToString
    • Finalize
inheritingobject program main
InheritingObject.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 test
InheritingObject.Test

class Test

{

override public string ToString()

{

return "覆寫InheritingObject.Test";

}

}

boxing unboxing
Boxing 與 Unboxing

int x = 10;

Object obj = (Object) x; // boxing

obj = 20;

int j = (int)obj; // unboxing

slide95
綱要
  • 預設類別System.Object
  • LSP: Liskov替代性原理
  • 抽象類別
  • DIP: 依存性反轉原理
  • 介面
  • ISP: 介面分離原理
  • 多重介面
  • *多重介面鑄形
liskov lsp liskov substitution principle
Liskov 代替性原理(LSP: Liskov Substitution Principle)
  • Subtype must be substitutable for their base types
  • 良好的繼承設計
    • 對形態S之每一物件o1,有形態T的物件o2,使在所有利用型態T物件的程式P中,P的行為不因以o1代替o2而改變
  • 破壞LSP常也破壞OCP

*Robert C. Martin, Agile Software Development: Principles, Patterns, and

Practices, Pearson Education, 2003

lspviolationexample rectangle 1 2
LSPViolationExample.Rectangle (1/2)

class Rectangle

{

private int width;

private int height;

virtual public int Width

{

set { width = value; }

}

virtual public int Height

{

set { height = value; }

}

lspviolationexample rectangle 2 2
LSPViolationExample.Rectangle (2/2)

public int Area()

{

return width * height;

}

}

lspviolationexample square
LSPViolationExample.Square

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
LSPViolationExample.Program

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);

}

}

slide102
函式的進入與離開條件
  • 進入與離開函式時的假設
  • Rectangle.Width的離開條件

Debug.Assert( (width == value) &&

(height == old.height));

  • 符合LSP之子類別函式覆寫的要求
    • 進入條件需等於父類別被覆寫函式之進入條件,或更寬鬆
    • 離開條件需等於父類別被覆寫函式之離開條件,或更嚴格
slide103
綱要
  • 預設類別System.Object
  • LSP: Liskov替代性原理
  • 抽象類別
  • DIP: 依存性反轉原理
  • 介面
  • ISP: 介面分離原理
  • 多重介面
  • *多重介面鑄形
abstractclassexample program main
AbstractClassExample.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 shape
AbstractClassExample.Shape

public abstract class Shape{

private string shape;

public Shape(string shape){

this.shape = shape;

Console.WriteLine("建立" + shape);

}

abstract public double Area();

}

abstractclassexample square
AbstractClassExample.Square

public class Square : Shape

{

double a;

public Square(double a): base("正方形")

{

this.a = a;

}

public override double Area()

{

return a * a;

}

}

abstractclassexample circle
AbstractClassExample.Circle

public class Circle : Shape

{

double r;

public Circle(double r): base("圓形")

{

this.r = r;

}

public override double Area()

{

return Math.PI * r * r;

}

}

slide109
練習
  • 將程式DrawingAllShapes中的類別Shape改為抽象類別,並將Shape.Draw()改為抽象函式
slide110
抽象類別
  • 修飾語
  • 欄位變數
  • 建構式
  • 函式方法覆寫與實作
slide111
綱要
  • 預設類別System.Object
  • LSP: Liskov替代性原理
  • 抽象類別
  • DIP: 依存性反轉原理
  • 介面
  • ISP: 介面分離原理
  • 多重介面
  • *多重介面鑄形
dip dependency inversion principle
依存性反轉原理(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

dipviolationexample lampstatus buttonstatus
DIPViolationExample.LampStatus及ButtonStatus

public enum LampStatus

{

OFF = 0,

ON = 1

}

public enum ButtonStatus

{

RELEASED = 0,

PRESSED = 1

}

dipviolationexample lamp
DIPViolationExample.Lamp

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 button 1 2
DIPViolationExample.Button (1/2)

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 button 2 2
DIPViolationExample.Button (2/2)

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 main 1 3
DIPViolationExample.Program.Main() 片段 (1/3)

Lamp lamp1 = new Lamp(1);

Button button = new Button(lamp1);

Random rand = new Random();

for (int n = 0; n <= 100; ++n)

{

Console.Write("time n = " + n + "\t");

dipviolationexample program main 2 3
DIPViolationExample.Program.Main() 片段 (2/3)

if (rand.Next() % 2 == 1)

{

if (button.Status ==

ButtonStatus.PRESSED)

{

button.Release();

}

else

{

button.Press();

}

}

dipviolationexample program main 3 3
DIPViolationExample.Program.Main() 片段 (3/3)

if (lamp1.Status == LampStatus.OFF)

{

Console.WriteLine("lamp1 is off");

}

else

{

Console.WriteLine("lamp1 is on");

}

Console.WriteLine();

}

slide122
綱要
  • 預設類別System.Object
  • LSP: Liskov替代性原理
  • 抽象類別
  • DIP: 依存性反轉原理
  • 介面
  • ISP: 介面分離原理
  • 多重介面
  • *多重介面鑄形
usinginterface program main
UsingInterface.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 shape
UsingInterface.Shape

interface Shape

{

double Area();

}

usinginterface square
UsingInterface.Square

public class Square : Shape

{

double a;

public Square(double a)

{

this.a = a;

}

public double Area()

{

return a * a;

}

}

usinginterface circle
UsingInterface.Circle

public class Circle : Shape

{

double r;

public Circle(double r)

{

this.r = r;

}

public double Area()

{

return Math.PI * r * r;

}

}

vs 1 2
介面 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
介面 vs. 抽象類別 (2/2)

public class Square : Shape{

. . .

public double Area(){

return a * a;

}

}

--------------------------------------------

public class Square : Shape{

. . .

public override double Area(){

return a * a;

}

}

buttonandlamp
ButtonAndLamp

public interface SwitchableDevice{

void TurnOn();

void TurnOff();

}

public enum LampStatus{

OFF = 0,

ON = 1

}

public enum ButtonStatus{

RELEASED = 0,

PRESSED = 1

}

buttonandlamp lamp
ButtonAndLamp.Lamp

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 button 1 2
ButtonAndLamp.Button (1/2)

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 button 2 2
ButtonAndLamp.Button (2/2)

public void Press(){

if (status == ButtonStatus.RELEASED){

status = ButtonStatus.PRESSED;

device.TurnOn();

}

}

public void Release(){

if (status == ButtonStatus.PRESSED){

status = ButtonStatus.RELEASED;

device.TurnOff();

}

}

}

slide135
練習
  • 在程式ButtonAndLamp增加類別Fan,使Button也可以控制Fan的開與關
slide136
綱要
  • 預設類別System.Object
  • LSP: Liskov替代性原理
  • 抽象類別
  • DIP: 依存性反轉原理
  • 介面
  • ISP: 介面分離原理
  • 多重介面
  • *多重介面鑄形
isp interface segregation principle
介面分離原理(ISP: Interface-Segregation Principle)
  • Clients should not be forced to depend on methods that they do not use
  • 避免同一介面中有目的不同的多群函式宣告
ispviolationexample
ISPViolationExample

interface TimerClient{

void TimeOut();

}

interface Door : TimerClient{

void Lock();

void Unlock();

bool IsOpen();

}

enum DoorStatus{

CLOSED = 0,

OPEN = 1

}

ispviolationexample timer 1 2
ISPViolationExample.Timer (1/2)

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 timer 2 2
ISPViolationExample.Timer (2/2)

public void Advance(){

++t;

if (t % timeout == 0){

client.TimeOut();

}

}

}

ispviolationexample timeddoor 1 2
ISPViolationExample.TimedDoor (1/2)

class TimedDoor : Door

{

private DoorStatus status =

DoorStatus.CLOSED;

public bool IsOpen(){

return (status == DoorStatus.OPEN);

}

public void Lock(){

if (IsOpen()) status = DoorStatus.CLOSED;

}

public void Unlock(){

if (!IsOpen()) status = DoorStatus.OPEN;

}

ispviolationexample timeddoor 2 2
ISPViolationExample.TimedDoor (2/2)

public void TimeOut(){

Lock();

}

}

ispviolationexample program main 1 2
ISPViolationExample.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 <= N; ++n)

{

ispviolationexample program main 2 2
ISPViolationExample.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();

}

slide146
綱要
  • 預設類別System.Object
  • LSP: Liskov替代性原理
  • 抽象類別
  • DIP: 依存性反轉原理
  • 介面
  • ISP: 介面分離原理
  • 多重介面
  • *多重介面鑄形
multiinterface program main
MultiInterface.Program.Main片段

Floatplane fp = new Floatplane();

fp.Sail();

fp.Fly();

multiinterface1
MultiInterface

interface Plane

{

void Fly();

}

interface Ship

{

void Sail();

}

multiinterface floatplane
MultiInterface.Floatplane

public class Floatplane : Plane, Ship{

public Floatplane(){

Console.WriteLine("建立水上飛機");

}

public void Sail(){

Console.WriteLine("水上滑行");

}

public void Fly(){

Console.WriteLine("空中飛行");

}

}

slide151
練習
  • 利用多重介面, 設計並測試一個類別Clock_Radio,兼具介面Clock之GetTime()與介面Radio之PlayMusic()功能
timeddoorsimulation
TimedDoorSimulation片段

interface TimerClient{

void TimeOut();

}

interface Door{

void Lock();

void Unlock();

bool IsOpen();

}

. . .

class TimedDoor : Door, TimerClient

{

. . .

}

slide154
綱要
  • 預設類別System.Object
  • LSP: Liskov替代性原理
  • 抽象類別
  • DIP: 依存性反轉原理
  • 介面
  • ISP: 介面分離原理
  • 多重介面
  • *多重介面鑄形
castmultiinterfaces program main
CastMultiInterfaces.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() );

}

castmultiinterfaces1
CastMultiInterfaces

interface Rectangle

{

double Area();

}

interface Rhombus

{

double Area();

}

castmultiinterfaces square 1 2
CastMultiInterfaces.Square (1/2)

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 square 2 2
CastMultiInterfaces.Square (2/2)

double Rectangle.Area()

{

return a * a;

}

double Rhombus.Area()

{

return 0.5 * d * d;

}

}

ad