0%

SOLID 筆記 - (1)OOP的四個特性

1. 在程式開發的過程會遇到各種情境

  • 開發的時間較長?還是維護的時間較長?

  • 有團隊一起進行開發?還是一個人寫CODE?

  • 一個長期維護的專案,需求變更的頻繁程度?

  • 你如何讓程式碼具備有可讀性擴充性

  • 如何避免修改程式的過程中引發連鎖反應?(改A壞B)

2. 物件導向程式設計的4個重要特性

2.1. 抽象

  • 將真實世界的需求轉換成為OOP中的類別
  • 類別可以包含狀態(屬性)與行為(方法)

例如我們要做一個CRM,然後分析需要哪些TABLE,接著建立出相對應的類別,類別裡面就有屬性跟方法,這個過程我們叫做抽象。

抽象是從需求轉換而來的

2.2. 封裝

  • 隱藏/保護內部實作的細節,並可以對屬性或方法設定存取層級(public,private,protected)。

2.3. 繼承

  • 可讓您建立新類別以重複使用、擴充和修改其他類別中定義的行為。

2.4. 多型

  • 在相同的介面下,可以用不同的型別來實現。
  • 多型有分成好幾種不同類型。

3. 從需求或規格中的進行”抽象化”的過程

  • 我們將建立新客戶管理系統
  • 該系統必須管理商業、住宅、政府、和教育類型的客戶
  • 我們必須最小程度地紀錄客戶的姓名姓氏名字電子郵件地址以及住家地址工作地址
  • 它必須管理產品,我們必須最小程度地記錄產品名稱描述當前價格

3.1. 透過”抽象化”過程定義出類別

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Customer
{
public int CustomerId { get; private set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string EmailAddress { get; set; }
public string HomeAddress { get; set; }
public string WorkAddress { get; set; }
public bool Validate() { return true; }
public void Save() { }
public void Load() { }
}

public class Product
{
public int ProductId { get; private set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public decimal? CurrentPrice { get; set; }
}

3.2. 對實作的細節進行”封裝”(隱藏、保護)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class Product
{
public Product(int productId)
{
this.ProductId = productId;
}

public int ProductId { get; private set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
private decimal? currentPrice;
public decimal? CurrentPrice
{
get { return currentPrice; }
set
{
if (value == null || value >= 0)
{
currentPrice = value;
}
else
{
currentPrice = null;
}
}
}

public Product Retrieve(int productId)
{
// 在這邊撰寫用來擷取Product物件的程式碼
return new Product();
}

protected bool Save()
{
// 在這邊撰寫用來儲存Product物件的程式碼
return true;
}

protected bool Validate()
{
var isValid = true;

if (string.IsNullOrWhiteSpace(ProductName))
isValid = false;
if (CurrentPrice == null)
isValid = false;

return isValid;
}
}

3.3. 透過”繼承”來重複利用、擴充和修改基底類別的定義

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class BaseClass
{
public string Name { get; set; }
public int Age { get; set; }
public virtual void Output() => Console.WriteLine("Hello");

public BaseClass(string name) => Name = name;
public BaseClass() => Name = ""; // 預設(無參數)建構函式
}

class DerivedClass : BaseClass
{
public string Department { get; set; }

public DerivedClass() : base("Default")
{
base.Age = 18; // 設定基底類別屬性
// base.Department = "IT"; // 基底類別沒有該屬性
base.Output(); // 執行基底類別方法

this.Age = 19; // 設定衍生類別屬性
this.Department = "IT";
this.Output(); // 執行衍生類別方法
}

public override void Output() => Console.WriteLine("Hello !!"); // 覆寫方法 (overriding)
}

3.4. 在C#中所有類型都是 “多型”

  • 在設計時期(Design Time)

    • 基底類別可以定義和實作「虛擬」屬性或方法(virtual)
    • 衍生類別可以「覆寫」這些虛擬的屬性或方法(override)
  • 在執行時期(Runtime)

    • 當手叫基底類別的虛擬方法時,會改呼叫子類別覆寫的方法

    • 常見的多型範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Shape
{
// A few example members
public int X { get; private set; }
public int Y { get; private set; }
public int Height { get; set; }
public int Width { get; set; }

// Virtual method
public virtual void Draw()
{
Console.WriteLine("Performing base class drawing tasks");
}
}

public class Circle : Shape
{
public override void Draw()
{
// Code to draw a circle...
Console.WriteLine("Drawing a circle");
base.Draw();
}
}
public class Rectangle : Shape
{
public override void Draw()
{
// Code to draw a rectangle...
Console.WriteLine("Drawing a rectangle");
base.Draw();
}
}
public class Triangle : Shape
{
public override void Draw()
{
// Code to draw a triangle...
Console.WriteLine("Drawing a triangle");
base.Draw();
}
}
  • 在C#中,所有類型都是多型類型

    • 因為所有類型(包括使用者定義的類型)都是繼承自Object
  • 如果要在C#中設計防止衍生類別覆寫虛擬成員

1
public sealed override void DoWork(){}
  • 多載(Overloading)比較有點爭議(有些人認為這不算多型)