灵活的班级设计,遵循开闭原则

时间:2019-02-17 11:34:55

标签: c# oop design-patterns

我正在处理一些应用程序,并进行了一些重构,以使其更加灵活。如我所料,出现了很多问题。 例如,我正在尝试寻找最佳方法从太空飞船类的集合中删除项目

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 :(得分:1)

根据经验,您不希望公开类型List的属性,尤其是如果它们不是只读的。我建议将WeaponsShields属性更改为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);
}

请注意,不再有繁琐的switch语句,几乎没有涉及特定设备类型的开关-除非您明确需要防护罩和武器。

当然,主要优点是,在添加新型设备时,您无需更改Spaceship类以支持它(当然,除非您想拥有专门的属性针对特定类型的设备,例如WeaponsShields)。