Interface segregation principle

介面隔離原則(Interface segregation principle):不應該讓一個類(class)為了實作某個介面(interface)而去讓這個類實作用不到的方法,簡單的說就是要避免一個大型的介面(interface)。最簡單的思考方向是使用單一職責(singleresponsibility principle)去考慮,讓每個介面保持單一並簡單。

假設要製作一個策略遊戲,這個遊戲有多個角色單位,每個單位會有血量,速度,等狀態,
可能會想將這些單位的狀態抽象為一個介面,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface IUnitStats
{
float Health { get; set; }
int Defense { get; set; }
void Die();
void TakeDamage();
void RestoreHealth();
float MoveSpeed { get; set; }
float Acceleration { get; set; }
void GoForward();
void Reverse();
void TurnLeft();
void TurnRight();
int Strength { get; set; }
int Dexterity { get; set; }
int Endurance { get; set; }
}

但是在遊戲中,有會有一些不可移動但是可以破壞的物件,這些物件也會需要生命值(Health),但是不需要移動相關的方法(如GoForward),因此這個介面太臃腫了。

可以考慮將這些行為切割為較小的介面,每個介面負責專一的職責

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface IMovable
{
float MoveSpeed { get; set; }
float Acceleration { get; set; }
void GoForward();
void Reverse();
void TurnLeft();
void TurnRight();
}
public interface IDamageable
{
float Health { get; set; }
int Defense { get; set; }
void Die();
void TakeDamage();
void RestoreHealth();
}
public interface IUnitStats
{
int Strength { get; set; }
int Dexterity { get; set; }
int Endurance { get; set; }
}

在實作時,敵人單位會移動,有狀態,並且是可損壞的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class EnemyUnit : MonoBehaviour, IDamageable, IMovable, IUnitStats
{
public float Health { get; set; }
public int Defense { get; set; }
public float MoveSpeed { get; set; }
public float Acceleration { get; set; }
public int Strength { get; set; }
public int Dexterity { get; set; }
public int Endurance { get; set; }

public void Die() { ... }
public void TakeDamage() { ... }
public void RestoreHealth() { ... }
public void GoForward() { ... }
public void Reverse() { ... }
public void TurnLeft() { ... }
public void TurnRight() { ... }
}

箱子只能被損壞

1
2
3
4
5
6
7
8
9
public class Box : MonoBehaviour, IDamageable
{
public float Health { get; set; }
public int Defense { get; set; }

public void Die() { ... }
public void TakeDamage() { ... }
public void RestoreHealth() { ... }
}

這樣,每個類只需要實作其所需的介面,避免了因為實作不必要的方法而增加的複雜性。

評論