Гибкий дизайн класса, который придерживается принципа «открыть-закрыть» - PullRequest
0 голосов
/ 17 февраля 2019

Я играю с каким-то приложением и выполняю небольшой рефакторинг, чтобы сделать его более гибким.Как я и ожидал, возникло много проблем.Например, я пытаюсь найти оптимальный способ удаления элементов из коллекций в классе космического корабля

class Spaceship{
 List<Weapon> Weapons {get;set;}
 List<Shield> Shields {get;set;}

 public void RemoveEquipment(Equipment item){
 switch(item.EquipmentType )
 {
   case EquipmentType.Weapon:
     weapons.Remove(item);
     break;
   case EquipmentType.Shield:
     shields.Remove(item);
     break;
 }    
 }

 public void AddEquipment(Equipment item){
 //works the same way as RemoveEquipment
 }

}

class Equipment{    
 //EquipmentType is enum
 EquipmentType Type {get;set;};
}

class Weapon: Equipment{    
}

class Shield:Equipment{
}

class AutoCannon:Weapon{
}

class LaserGun:Weapon {

}

Есть ли лучший способ?Что делать, если я хочу удалить группу предметов одного и того же подтипа (например, каждый LaserGun в коллекции оружия - без использования отражения) И если я хочу добавить новый тип экипировки, методы, отвечающие за добавление / удаление, должны быть изменены (переключатель/дело).

1 Ответ

0 голосов
/ 17 февраля 2019

Как правило, вы не хотите раскрывать свойства типа List, особенно если они не доступны только для чтения.Я бы предложил изменить свойства Weapons и Shields на IEnunerable или по крайней мере IReadOnlyList - и сделать их доступными только для чтения.

Сказав это, ваш класс Spaceship может выглядеть следующим образомэто:

// internal is the default access modifier for types, but it's more descriptive to specify it. 
internal class Spaceship
{

    private List<Equipment> _equipment = new List<Equipment>();

    public IEnumerable<Weapon> Weapons {get {return _equipment.OfType<Weapon>();}}
    public IEnumerable<Shield> Shields {get {return _equipment.OfType<Shield>();}}

    public void RemoveEquipment(Equipment item)
    {
        _equipment.Remove(item);
    }

    public void AddEquipment(Equipment item)
    {
        _equipment.Add(item);
    }

}

И затем, чтобы удалить все оборудование определенного типа, вы можете сделать что-то вроде этого:

public void RemoveEquipment<T>() where T : Equipment
{
    _equipment.RemoveAll(e => e is T);
}

Вы также можете добавить группу оборудования нав то же время:

public void AddEquipment(IEnumerable<Equipment> items)
{
    _equipment.AddRange(items);
}

Обратите внимание, что больше нет громоздких переключателей и почти ничего, связанного с конкретным типом оборудования - кроме случаев, когда вам явно нужны щиты и оружие.

Основнойвыгода, конечно, заключается в том, что при добавлении нового типа оборудования вам не нужно менять класс Spaceship для его поддержки (если, конечно, вы не хотите иметь свойство, специализированное для этого конкретного типа оборудования, такого какWeapons или Shields).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...