“基类params并不总是使用”代码气味

时间:2011-10-17 10:41:32

标签: c# oop design-patterns

假设你有这样的代码:

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 个答案:

答案 0 :(得分:2)

您可以在此处使用对象作为参数;这种情况通常用于参数数量因使用的呼叫而异的情况。

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)
    {
    }
}

答案 1 :(得分:0)

在Registrator3中是否无法包含externalParam的逻辑? 换句话说,Registrator3使用param,然后调用未修改的无参数基础?

很大程度上取决于逻辑所属的位置。如果它是base的内在属性,那么将它放在base中,并重载Register()函数或为param提供一个默认值,以便子类不需要提供它。

答案 2 :(得分:0)

假设您要重用基类中的注册逻辑,可以按如下方式更新代码:

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,

科斯明

编辑:更新了要编译的代码。