Что мне нужно изменить, чтобы правильно реализовать дизайн SOLID? - PullRequest
3 голосов
/ 20 октября 2019

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

Я бы хотел, чтобы класс Player требовал только один метод для экипировки, поэтому мне нужна помощь в понимании того, что ясделали неправильно и как это сделать правильно.

Упрощенная версия моих интерфейсов:

    interface IItem
    {
        string Name { get; set; }
        int Value { get; set; }
        Quality Quality { get; set; }
        EquipmentType Type { get; set; }
    }
    interface IWeapon : IItem
    {

    }
    interface IArmour : IItem
    {
        int Defence { get; set; }
        Slot Slot { get; set; }
    }

Класс потребителя Player:

    class Player
    {
        private Dictionary<Slot, IArmour> armour = new Dictionary<Slot, IArmour>();
        private IWeapon weapon;

        public bool Equip(IItem item)
        {
            switch (item.Type)
            {
                case EquipmentType.Armour:
                    var armour = item as IArmour;
                    if (this.armour.ContainsKey(armour.Slot))
                    {
                        return false;
                    }
                    this.armour.Add(armour.Slot, armour);
                    return true;
                case EquipmentType.Weapon:
                    var weapon = item as IWeapon;
                    throw new NotImplementedException();
                default:
                    return false;
            }
        }
    }

Перечисления для контекста:

    enum Slot
    {
        Head = 0,
        Soulders = 1,
        Gloves = 2,
        Neck = 3,
        RRing = 4,
        LRing = 5,
        Torso = 6,
        Legs = 7,
        Boots = 8,
        Bracers = 9,
        Belt = 10,
    }
    enum EquipmentType
    {
        Armour = 0,
        Weapon = 1
    }

1 Ответ

5 голосов
/ 20 октября 2019

Принцип замены Лискова , как правило, о том, как вы определяете свои классы. Если вы пишете класс, который является производным от некоторого другого класса (или реализует некоторый интерфейс), идея заключается в том, что кто-то должен иметь возможность использовать ваш класс, как если бы он был экземпляром этого родительского класса. Ваш подкласс может иметь дополнительное поведение, которого родительский класс не имеет (и тот, кто использует ваш класс, как если бы он был экземпляром родительского класса, конечно, не сможет получить к нему доступ), но все поведение, котороеродительский класс должен оставаться неизменным в дочернем классе.

В вашем примере это может означать определение MagicalWholeBodyArmor, которое не вписывается в Slot, и поэтому выдает исключение, если вы пытаетесь получить доступего Slot свойство. Кто-то, кто обращается с MagicalWholeBodyArmor, как с IArmor, будет удивлен, когда попытается увидеть, в какой слот он вписывается.

Правило SOLID, которое код немного нарушает, Принцип открытия / закрытия . Хорошее практическое правило для принципа Open / Closed: «Если я изменю этот бит кода, сколько других битов кода в других местах мне также придется изменить?». Если ответ «много», то это, вероятно, потому, что вы нарушаете принцип Open / Closed.

В вашем случае добавление нового члена enum EquipmentType означает, что вам придется пойти и найтиэтот оператор switch в вашем классе Player и добавьте новый регистр.

Если есть только один оператор switch, то это не так уж плохо. Если вы добавляете новый тип оборудования, тогда вашему классу Player, вероятно, потребуется обновить в любом случае , поэтому изменение оператора switch как части этого вполне подойдет. Попытка обдумать это будет означать значительную абстракцию при очень небольшом усилении.

Однако, если у вас есть много-много операторов switch во многих разных местах, которые все смотрят на EquipmentType, (и принимать различные решения на его основе), и вам нужно будет найти их все и исправить их, тогда это будет большим нарушением принципа Open / Closed, и это, вероятно, является признаком того, что вам нужно реорганизовать вещи так, чтобывсе эти отдельные, разрозненные кусочки логики в одном месте.

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