Inheritance and polymorphism
This presentation is the property of its rightful owner.
Sponsored Links
1 / 159

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


  • 55 Views
  • Uploaded on
  • Presentation posted in: General

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

Download Presentation

繼承與多型 (Inheritance and Polymorphism)

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)

鄭士康

國立台灣大學

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

資訊網路與多媒體研究所


Inheritance and polymorphism

綱要

  • 繼承

  • 修飾語protected

  • 限制繼承

  • 繼承架構下的建構函式呼叫

  • OCP:開放-封閉原理

  • 多型

  • 覆寫與隱藏

  • 二十一點模擬程式0.1版


Inheritance and polymorphism

綱要

  • 預設類別System.Object

  • LSP: Liskov替代性原理

  • 抽象類別

  • DIP: 依存性反轉原理

  • 介面

  • ISP: 介面分離原理

  • 多重介面

  • *多重介面鑄形


Inheritance and polymorphism

綱要

  • 繼承

  • 修飾語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;

}

}


Inheritance and polymorphism

表示繼承的UML類別圖


Inheritance and polymorphism

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

}


Inheritance and polymorphism

物件記憶體分配模型

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


Inheritance and polymorphism

練習

  • 實作並測試下列繼承關係


Inheritance and polymorphism

綱要

  • 繼承

  • 修飾語protected

  • 限制繼承

  • 繼承架構下的建構函式呼叫

  • OCP:開放-封閉原理

  • 多型

  • 覆寫與隱藏

  • 二十一點模擬程式0.1版


Calculatorinheritance

CalculatorInheritance類別圖


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

}

}


Inheritance and polymorphism

綱要

  • 繼承

  • 修飾語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; }

}

}


Inheritance and polymorphism

綱要

  • 繼承

  • 修飾語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()" );

}

}


Inheritance and polymorphism

衍生物件產生流程

Primate human = new Primate( 4 );

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

{

. . .

}

public Animal( string s )

{

. . .

}


Inheritance and polymorphism

練習

  • 利用偵錯器體驗了解程式UsingConstructorsForInheritance


Inheritance and polymorphism

綱要

  • 繼承

  • 修飾語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

程式OCPViolationExample類別圖


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函式


Inheritance and polymorphism

綱要

  • 繼承

  • 修飾語protected

  • 限制繼承

  • 繼承架構下的建構函式呼叫

  • OCP:開放-封閉原理

  • 多型

  • 覆寫與隱藏

  • 二十一點模擬程式0.1版


Inheritance and polymorphism

物件導向的關鍵技術

  • 封裝(packaging)

  • 繼承(inheritance)

  • 多型(polymorphism)


Inheritance and polymorphism

多型

  • 編譯時連結(compile-time binding)與執行時連結(run-time binding)

    • 靜態連結(static binding)與動態連結(dynamic binding)

  • 多型之要求

    • 繼承階層體系

    • 虛擬(virtual)與覆寫(override)

    • 基礎類別之參考

  • 多型之優缺點


Drawingallshapes

DrawingAllShapes類別圖


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


Inheritance and polymorphism

練習

  • 在程式DrawingAllShapes增加類別Triangle,使程式也能畫出三角形。


Inheritance and polymorphism

綱要

  • 繼承

  • 修飾語protected

  • 限制繼承

  • 繼承架構下的建構函式呼叫

  • OCP:開放-封閉原理

  • 多型

  • 覆寫與隱藏

  • 二十一點模擬程式0.1版


Newvsoverride program

NewVsOverride.Program類別圖


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

}


Inheritance and polymorphism

覆寫與隱藏

  • 覆寫: override

    • 主要用於Polymorphism (多型)

    • 執行時連結

  • 隱藏: new

    • 只是取代基底類別同名之成員變數與方法

    • 仍是編譯時連結


Inheritance and polymorphism

練習

  • 利用偵錯器體驗了解程式NewVsOverride


Inheritance and polymorphism

綱要

  • 繼承

  • 修飾語protected

  • 限制繼承

  • 繼承架構下的建構函式呼叫

  • OCP:開放-封閉原理

  • 多型

  • 覆寫與隱藏

  • 二十一點模擬程式0.1版


Blackjack 0 1

BlackJack_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<N_PLAYERS; ++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<N_PLAYERS-1; ++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);

}

}


Inheritance and polymorphism

綱要

  • 預設類別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


Inheritance and polymorphism

綱要

  • 預設類別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


Inheritance and polymorphism

IS-A 關係與繼承


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

}

}


Inheritance and polymorphism

函式的進入與離開條件

  • 進入與離開函式時的假設

  • Rectangle.Width的離開條件

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

    (height == old.height));

  • 符合LSP之子類別函式覆寫的要求

    • 進入條件需等於父類別被覆寫函式之進入條件,或更寬鬆

    • 離開條件需等於父類別被覆寫函式之離開條件,或更嚴格


Inheritance and polymorphism

綱要

  • 預設類別System.Object

  • LSP: Liskov替代性原理

  • 抽象類別

  • DIP: 依存性反轉原理

  • 介面

  • ISP: 介面分離原理

  • 多重介面

  • *多重介面鑄形


Inheritance and polymorphism

抽象類別


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;

}

}


Inheritance and polymorphism

練習

  • 將程式DrawingAllShapes中的類別Shape改為抽象類別,並將Shape.Draw()改為抽象函式


Inheritance and polymorphism

抽象類別

  • 修飾語

  • 欄位變數

  • 建構式

  • 函式方法覆寫與實作


Inheritance and polymorphism

綱要

  • 預設類別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


Inheritance and polymorphism

一個違反DIP的例子


State chart

狀態圖(State Chart)


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

}


Inheritance and polymorphism

綱要

  • 預設類別System.Object

  • LSP: Liskov替代性原理

  • 抽象類別

  • DIP: 依存性反轉原理

  • 介面

  • ISP: 介面分離原理

  • 多重介面

  • *多重介面鑄形


Inheritance and polymorphism

介面


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;

}

}


Inheritance and polymorphism

一個符合DIP的設計


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

}

}

}


Inheritance and polymorphism

練習

  • 在程式ButtonAndLamp增加類別Fan,使Button也可以控制Fan的開與關


Inheritance and polymorphism

綱要

  • 預設類別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

  • 避免同一介面中有目的不同的多群函式宣告


Inheritance and polymorphism

一個違反ISP的例子


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

}


Inheritance and polymorphism

綱要

  • 預設類別System.Object

  • LSP: Liskov替代性原理

  • 抽象類別

  • DIP: 依存性反轉原理

  • 介面

  • ISP: 介面分離原理

  • 多重介面

  • *多重介面鑄形


Multiinterface

程式MultiInterface類別圖


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("空中飛行");

}

}


Inheritance and polymorphism

練習

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


Inheritance and polymorphism

一個符合ISP的設計


Timeddoorsimulation

TimedDoorSimulation片段

interface TimerClient{

void TimeOut();

}

interface Door{

void Lock();

void Unlock();

bool IsOpen();

}

. . .

class TimedDoor : Door, TimerClient

{

. . .

}


Inheritance and polymorphism

綱要

  • 預設類別System.Object

  • LSP: Liskov替代性原理

  • 抽象類別

  • DIP: 依存性反轉原理

  • 介面

  • ISP: 介面分離原理

  • 多重介面

  • *多重介面鑄形


Castmultiinterfaces

程式CastMultiInterfaces類別圖


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;

}

}


  • Login