Adicionando um novo método a uma biblioteca de classes para sua nova versão e expondo uma opção de versão, os usuários podem selecionar

4

É uma má idéia adicionar um novo método (que implementa um novo algoritmo) a uma biblioteca de classes para sua nova versão e expor uma opção de versão que os consumidores possam selecionar?

É apenas para compatibilidade com versões anteriores, em que um aplicativo antigo pode precisar de uma sequência constante de números aleatórios para um determinado número de semente.

O código a seguir pode falar muito melhor a minha ideia. Espero que você consiga a essência.

//Class Library:
namespace MyGenerator
{
    public sealed class MyRandom
    {
        public enum Version { One, Two }// add more options in the future 
        private int current;
        private Version version;

        public MyRandom(int seed, Version version = Version.One)
        {
            current = seed;
            this.version = version;
        }

        public int Next()
        {
            switch (version)
            {
                case Version.One:
                    AlgorithmOne();
                    break;
                case Version.Two:
                    AlgorithmTwo();
                    break;
                // add more options in the future
            }
            return current;
        }

        private int AlgorithmOne()
        {
            current = (current * 1234567890 + 987654321) & 0x7FFFFFFF;
            return current;
        }

        private int AlgorithmTwo()
        {
            current = (current * current + current) & 0x7FFFFFFF;
            return current;
        }
        // add more algorithm in the future
    }
}

e

//Console Application (for testing purposes):

using MyGenerator;
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            const int seed = 12345;
            MyRandom rnd = new MyRandom(seed, MyRandom.Version.Two);
            Console.WriteLine(rnd.Next());
            Console.ReadLine();
        }
    }
}
    
por kiss my armpit 03.01.2014 / 04:37
fonte

4 respostas

11

Não, nunca faça isso. Se você deseja projetar para futuras versões, use os padrões orientados a objetos projetados especificamente para esse . Por exemplo, eis como resolvo o seu problema:

abstract class MyRandom
{
    // Ensure that a third party cannot extend the base
    // class by making the ctor private.
    private MyRandom() {}

    public abstract int Next();

    private class First : MyRandom
    {
        // whatever
    } 

    private class Second : MyRandom
    {
        // whatever
    } 

    // Chef's choice:
    public static MyRandom MakeRandom() { return new Second(); }

    // Diner's choice:
    public static MyRandom MakeFirst() { return new First(); }
    public static MyRandom MakeSecond() { return new Second(); }
}

Quando você deseja adicionar uma nova versão, esse é um detalhe de implementação particular da classe , e então adiciona um novo método de fábrica estático . Se o chamador quiser que você escolha a melhor versão, ele chama o método que lhe permite decidir. Se eles têm uma versão específica que eles querem, eles chamam um método que lhes dá isso.

Mais algumas orientações:

  • Se você acredita que adicionará mais membros a um enum no futuro, provavelmente está fazendo algo errado. O conjunto de itens em um enum deve ser idêntico para sempre.

  • Se você estiver usando uma opção não-flags com n opções e fazendo n coisas diferentes como resultado, apenas escreva n métodos .

por 03.01.2014 / 18:27
fonte
10

Ter um parâmetro de versão estaria sujo.

É uma mistura flagrante de preocupações. A primeira preocupação é o que o método deve fazer. A segunda preocupação como gerenciar várias versões conflitantes de uma API massiva. Os dois são completamente não relacionados e devem permanecer o mais separados possível.

Como desenvolvedor, estou interessado apenas na primeira preocupação ( o que o método deve fazer). Se eu tentar chamar Math.Random e, de repente, há um parâmetro para a versão ... bem, eu vou ficar confuso. O que o controle de versão tem a ver com a aleatoriedade?

Em outras palavras, adicionar um parâmetro de versão forçaria o desenvolvedor a tomar conhecimento da implementação de Math.Random (e seu histórico) em vez de apenas saber o que se espera que ele faça. Na minha opinião, isso tornaria uma API muito ruim.

    
por 03.01.2014 / 12:24
fonte
4

A resposta provável é ... porque eles não querem.

Parece que eles estão deixando sua opção em aberto para mudar para um algoritmo PRNG diferente, se um novo que eles preferirem vir. Existe também a possibilidade de que futuros tempos de execução do .NET para plataformas inteiramente novas possam exigir algo diferente em termos de um algoritmo PRNG, para que eles não queiram se trancar em um determinado algoritmo.

Eles não precisam fornecer versões anteriores de seus geradores, porque eles são simples dizendo que você não deve confiar nele para obter resultados previsíveis. O objetivo é retornar um número aleatório de psuedo. Não é uma sequência reproduzível de números. Não há razão para se preocupar com qual versão do algoritmo eles estão usando, porque você está chamando para obter um número aleatório.

Se você precisar de resultados previsíveis, deverá implementar seu próprio gerador de números aleatórios (de preferência usando um dos algoritmos mais bem testados e conhecidos).

    
por 03.01.2014 / 05:29
fonte
2

É uma ideia interessante. No entanto, eu provavelmente amaldiçoaria o desenvolvedor da biblioteca quando tento usar um método como este. Da perspectiva do usuário, isso torna a biblioteca muito mais complicada de entender.

Neste caso específico, irei para o padrão Método de modelo . Vou criar uma classe abstrata "Random" e fazer do "MyRandom" existente sua subclasse.

Depois disso, eu posso implementar o algoritmo B em outra nova subclasse ("YourRandom", "HisRandom" :)) O código existente não irá quebrar, o novo uso pode selecionar o algoritmo para aleatório.

    
por 03.01.2014 / 16:20
fonte

Tags