Pergunta

Eu tenho um objeto de Pessoa com dois construtores - um leva um int (personId), o outro de uma seqüência de caracteres (logonName).Eu gostaria de um outro construtor que recebe uma string (badgeNumber).Eu sei que isso não pode ser feito, mas parece que pode ser uma situação comum.Existe uma graciosa maneira de lidar com isso?Suponho que isto se aplica a qualquer método sobrecarregado.Código:

public class Person
{
    public Person() {}

    public Person(int personId)
    {
        this.Load(personId);
    }

    public Person(string logonName)
    {
        this.Load(logonName);
    }

    public Person(string badgeNumber)
    {
        //load logic here...
    }

...etc.

Foi útil?

Solução

Você pode considerar o uso de tipos personalizados.

Por exemplo, criar LogonName e BadgeNumber classes.

Em seguida, a sua função de declarações parecer...

public Person(LogonName ln)
{
    this.Load(ln.ToString());
}

public Person(BadgeNumber bn)
{
    //load logic here...
}

Tal solução pode dar-lhe um bom lugar para manter a lógica de negócios que controla o formato e o uso dessas seqüências.

Outras dicas

Talvez você poderia usar métodos de fábrica em vez disso?

public static Person fromId(int id) {
    Person p = new Person();
    p.Load(id);
    return p;
}
public static Person fromLogonName(string logonName) {
    Person p = new Person();
    p.Load(logonName);
    return p;
}
public static Person fromBadgeNumber(string badgeNumber) {
    Person p = new Person();
    // load logic
    return p;
}
private Person() {}

Você tem quatro opções que eu posso pensar, três dos quais já foram nomeados por outros:

  1. Vá a fábrica de rota, como sugerido por vários outros aqui.Uma desvantagem é que você não pode ter de nomenclatura consistente, através de sobrecarga (ou outra coisa que você deseja ter o mesmo problema), então é superficialmente menos limpa.De outro, maior, a desvantagem é que ele impede a possibilidade de alocar diretamente na pilha.Tudo vai ser alocado no heap se você tomar essa atitude.

  2. Objeto personalizado wrappers.Esta é uma boa abordagem, e o que eu recomendo se você estiver começando do zero.Se você tem um monte de código usando, por exemplo, emblemas como cadeias de caracteres, então reescrever o código pode fazer que este não é um opção viável.

  3. Adicionar uma enumeração para o método, especificar como tratar a cadeia.Isso funciona, mas requer que você reescrever todas as chamadas existentes para incluir a nova enumeração (apesar de que você pode fornecer um padrão, se desejar, para evitar algumas dessas).

  4. Adicionar um parâmetro fictício que não é utilizada para distinguir entre as duas sobrecargas.exemplo:Virar uma bool para o método.Esta abordagem é tomada pela biblioteca padrão em alguns lugares, por exemplo, std::nothrow é um parâmetro fictício para operator new.As desvantagens dessa abordagem são o que é feio e que ele não escala.

Se você já possui uma grande base de código existente, eu recomendo adicionar a enumeração (possivelmente com um valor padrão) ou adicionando o parâmetro fictício.Nem é bonito, mas ambos são bem simples de retrofit.

Se você estiver começando do zero, ou apenas ter uma pequena quantidade de código, eu recomendo o objeto personalizado wrappers.

Os métodos de fábrica seria uma opção se você tiver o código que usa muito a raw badge/logonName cadeias de caracteres, mas não usam muito o Person de classe.

Se você estiver usando o C# 3.0, você pode usar Os Inicializadores De Objeto:

public Person()
{
}

public string Logon { get; set; }
public string Badge { get; set; }

Você deve chamar o construtor como este:

var p1 = new Person { Logon = "Steve" };
var p2 = new Person { Badge = "123" };

Não.

Você pode considerar um campo de sinalizador (enum para facilitar a leitura) e, em seguida, ter o construtor usar htat para determinar o que você quis dizer.

Que não funcionam.Você pode considerar em fazer uma classe chamada BadgeNumber que envolve uma seqüência de caracteres, a fim de evitar essa ambigüidade.

Você não pode ter dois diferentes construtores/métodos com a mesma assinatura, caso contrário, como pode o compilador determinar qual o método a executar.

Como Zack disse:, Eu gostaria de considerar a criação de um "opções" classe onde você pode passar os parâmetros contidos em um tipo personalizado.Isso significa que você pode muito bem passar parâmetros como muitos como você gosta e fazer o que quiser com as opções, basta ter cuidado para não criar um monolítico método que tenta fazer de tudo..

Ou isso, ou voto, para o padrão de fábrica..

Você pode usar um estático método de fábrica:

public static Person fromLogon(String logon) { return new Person(logon, null); }
public static Person fromBadge(String badge) { return new Person(null, badge); }

Como tem sido sugerido, tipos personalizados é o caminho a percorrer neste caso.

Única coisa que posso pensar para lidar com o que você está querendo fazer é ter a params, que descreve o param tipo (um enum com LogonName BadgeNumer, etc) e o segundo é o valor param.

Você poderia mudar para uma fábrica padrão do estilo.

public class Person {

  private Person() {}

  public static PersonFromID(int personId)
  {
    Person p = new Person().
    person.Load(personID);

    return p;
    this.Load(personId);
  }

  public static PersonFromID(string name)
  {
    Person p = new Person().
    person.LoadFromName(name);

    return p;
  }

  ...
}

Ou, como sugestão, utilizar tipos personalizados.Você também pode hackear algo usando generics, mas eu não recomendo isso para facilitar a leitura.

Como sobre ...

public Person(int personId)
{
    this.Load(personId);
}

public Person(string logonName)
{
    this.Load(logonName);
}

public Person(Object badgeNumber)
{
    //load logic here...
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top