«Параметры базового класса не всегда используются» код запаха - PullRequest
0 голосов
/ 17 октября 2011

Предположим, у вас был такой код:

public Base
{
   abstract void Register();
}

public Registrator1: Base
{
   override void Register()
   {
      //uses the current state of the object to populate the UI captions
   }
}

public Registrator2: Base
{
   override void Register()
   {
      //uses the current state of the object to populate the UI captions
   }
}

Но когда вы получаете новое бизнес-правило, в котором вас просят написать Registrator3, который фактически регистрируется на основе какого-либо параметра, и вы меняете кодовую базу следующим образом:

public Base
{
   abstract void Register(externalParam);
}

public Registrator1: Base
{
   override void Register(externalParam)
   {
      //uses the current state of the object to populate theUI
   }
}

public Registrator2: Base
{
   override void Register(externalParam)
   {
      //uses the current state of the object to populate the UI
   }
}

public Registrator3: Base
{
   override void Register(externalParam)
   {
     //uses a DDD - service passed in the params to populate the UI
   }
}

Но Registrator1 и Registrator2 этот параметр не нужен, и код становится вонючим. Как можно переписать этот код?

Ответы [ 3 ]

2 голосов
/ 17 октября 2011

Вы можете использовать объект в качестве параметра здесь; который обычно используется в сценариях, где количество параметров может варьироваться в зависимости от используемого вызова.

struct RegistrationInfo
{
    public static readonly RegistrationInfo Empty = new RegistrationInfo();
    public string Username;
    public string CustomerName;
    public string Validity; 
}

abstract class Base
{
    public abstract void Register(RegistrationInfo info);
    // If you want to retain the paramaterless call:
    public void Register()
    {
         Register(RegistrationInfo.Empty);
    }
}

class Registrar1 : Base
{
    public override void Register(RegistrationInfo info)
    {
        if (info.Username == null) throw new ArgumentNullException("info.Username");
    }
}

class Registrar2 : Base
{
    public override void Register(RegistrationInfo info)
    {
        if (info.CustomerName == null) throw new ArgumentNullException("info.CustomerName");
    }
}

Это имеет то преимущество, что вам не нужно изменять параметры метода (что нарушает интерфейс) каждый раз, когда добавляется параметр. Использование также становится несколько самодокументированным:

var r = new Registrar1();
r.Register(new RegistrationInfo(){ Username = "JimJoe" });
r.Register(RegistrationInfo.Empty);

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

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

class RegistrationInfo
{

}

class RegistrationInfo1 : RegistrationInfo
{
    public string Arg;
}

class RegistrationInfo2 : RegistrationInfo
{
    public int Arg;
}

interface IBase<in TRegistration>
    where TRegistration : RegistrationInfo
{
    void Register(TRegistration registration);
}

class Base : IBase<RegistrationInfo>
{
    public void Register(RegistrationInfo registration)
    {

    }
}

class Registrar1 : IBase<RegistrationInfo1>
{
    public void Register(RegistrationInfo1 arg)
    {
    }
}

class Registrar2 : IBase<RegistrationInfo2>
{
    public void Register(RegistrationInfo2 arg)
    {
    }
}
0 голосов
/ 17 октября 2011

Если вы хотите повторно использовать логику регистрации из базового класса, вы можете обновить код следующим образом:

public class Base
{
   public virtual void Register(object externalParam)
   {
       // base registration logic goes here
   }
}

public class Registrator1: Base
{
   public override void Register(object externalParam)
   {
       base.Register(null);
       // custom registration logic goes here
   }
}

public class Registrator2: Base
{
   public override void Register(object externalParam)
   {
       base.Register(null);
       // custom registration logic goes here
   }
}

public class Registrator3: Base
{
   public override void Register(object externalParam)
   {
       base.Register(externalParam);
       // custom registration logic goes here
   }
}

HTH,

Cosmin

РЕДАКТИРОВАТЬ:Обновлен код для компиляции.

0 голосов
/ 17 октября 2011

Разве невозможно содержать логику для externalParam в Registrator3?Другими словами, Registrator3 использует параметр, а затем вызывает неизмененную базу без параметров?

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

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