Pergunta

Eu escrevi recentemente uma classe que torna curvas B-spline. Estas curvas são definidos por um número de pontos de controlo. Originalmente, eu tinha a intenção de usar oito pontos de controle, então eu adicionei uma constante para a classe, assim:

class Curve
{
   public:
      static const int CONTROL_POINT_COUNT = 8;
};

Agora eu quero estender esta classe para permitir que uma quantidade arbitrária de pontos de controle. Então eu quero mudar isso para:

class Curve
{
   public:
      int getControlPointCount() {return _controlPointCount;}
};

A questão é se não melhor é armazenar constantes em métodos para começar, para facilitar a adaptabilidade. Em outras palavras, não é melhor ter começado assim:

class Curve
{
   public:
      int getControlPointCount() {return 8;}
};

A vantagem disto é que eu poderia ter apenas mudou um símbolo no método em questão, em vez de se movimentar constantes etc.

Esta é uma boa prática ou ruim?

Foi útil?

Solução

Normalmente sou a favor de manter o menor número de acoplamentos manualmente possível.

O número de pontos de controlo na curva é, assim, o número de pontos de controlo na curva. Não é uma variável independente que pode ser ajustado à vontade.

Então, eu costumo exporia uma referência contêiner padrão const:

class Curve
{   
    private:
        std::vector<Point>& _controlPoints;

    public:      
        Curve ( const std::vector<Point>& controlPoints) : _controlPoints(controlPoints)
        {
        }

        const std::vector<Point>& getControlPoints ()
        {
            return _controlPoints;
        }
};

E se você quiser saber quantos pontos de controle, em seguida, usar curve.getControlPoints().size(). Eu suspeito que, na maioria dos casos de uso que você iria querer os pontos, bem como a contagem de qualquer maneira, e expondo um contêiner padrão que você pode usar a expressões idiomáticas iteradoras e built-in algoritmos da biblioteca padrão, em vez recebendo a contagem e chamada uma função como getControlPointWithIndex num ciclo.

Se não há realmente nada mais na classe curva, eu poderia até mesmo ir tão longe como:

typedef std::vector<Point> Curve;

(muitas vezes uma curva não vai tornar-se, como uma classe processador pode ter detalhes sobre o pipeline de processamento, deixando uma curva como puramente o artefato geométrica)

Outras dicas

int getControlPointCount() {return _controlPointCount;}

Este é um acessor. Trocar uma estática const para um acessor não é realmente um ganho como litb assinalou. O que você realmente precisa para à prova de futuro é provavelmente um par de acessor e modificador.

int getControlPointCount() {return _controlPointCount;} // accessor

Eu também jogar em um projeto-const para o acessor e torná-lo:

int getControlPointCount() const {return _controlPointCount;} // accessor

e o correspondente:

void setControlPointCount(int cpc) { _controlPointCount = cpc;} //mutator

Agora, a grande diferença com um objeto estático é que a contagem de ponto de controle não é mais um atributo de nível de classe mas um nível de instância. Esta é uma alteração de design . Você quer que ele desse jeito?

Nit:. A contagem estática nível de classe é public e, portanto, não precisa de um sistema de acesso

Para responder melhor a sua pergunta, a pessoa também deve saber como a variável controlPointCount está definido. É definido fora de sua classe? Neste caso, você também deve definir um setter. Ou a classe Curve é o único responsável por defini-lo? É definido apenas em tempo de compilação ou também em tempo de execução.

De qualquer forma, evitar um número mágico, mesmo nesta forma:

int getControlPointCount() {return 8;}

Este é melhor:

int getControlPointCount() {return CONTROL_POINT_COUNT;}

Um método tem a vantagem de que você pode modificar a implementação interna (use um valor constante, ler a partir de um arquivo de configuração, alterar o valor dinamicamente), sem afetar o externo da classe.

class Curve
{   
    private:
        int _controlPointCount;

        void setControlPointCount(int cpc_arg)
        {
            _controlPointCount = cpc_arg;
        }

    public:      
        curve()
        {
            _controlPointCount = 8;
        }

        int getControlPointCount() const
        {
            return _controlPointCount;
        }
};

Vou criar um código como este, com a função set em privado, de modo que nenhum corpo pode jogar com contagem de pontos de controle, até que passar para a próxima fase da development..where atualização começamos a atualizar a contagem de ponto de controle em tempo de execução. naquele tempo, podemos passar este método set do privado ao alcance do público.

Enquanto a compreensão da questão, tenho uma série de problemas conceituais com o exemplo:

  • O que é o valor de retorno para getControlPointCount() quando o número de pontos de controle não é limitado?
    • É MAXINT?
    • É o número atual de pontos de controle na curva (quebrando assim a lógica que diz que este é o maior número possível de pontos?)
  • O que acontece quando você realmente tentar criar uma curva com pontos maxint? Você vai ficar sem memória eventualmente.

A interface em si parece problemático para mim. Como outras classes de coleção padrão, a classe deveria ter encapsulado sua limitação no número de pontos, e sua AddControlPoint() deveria ter retornado um erro se uma limitação do tamanho, memória ou qualquer outra violação ocorreu.

Quanto à resposta específica, eu concordo com kgiannakakis: a função de membro permite mais flexibilidade

.

I tendem a usar a configuração + constante (valor padrão) para todos os valores 'estável' através da execução do programa. Com constantes simples para valores que não pode mudar (360 graus -> 2 pi radianos, 60 segundos -> 1 minuto). Ou cujos mudança iria quebrar o código de execução (mínimo / valores máximos para os algoritmos que os tornam instáveis)

Você está lidando com alguns problemas de design diferentes. Primeiro você deve saber se o número de pontos de controle é um valor do nível de classe ou instância. Então se é uma constante em qualquer um dos dois níveis.

Se todas as curvas devem compartilhar o mesmo número de pontos de controle em sua aplicação então é um valor de nível de classe (estática). Se diferentes curvas pode ter um número diferente de pontos de controle, então não é um valor de nível de classe, mas sim um nível de instância um.

Neste caso, se o número de pontos de controle será constante durante toda a vida da curva, então é uma constante nível de instância, se ele pode mudar, então não é constante a este nível também.

// Assuming that different curves can have different 
// number of control points, but that the value cannot 
// change dynamically for a curve.
class Curve
{
public:
   explicit Curve( int control_points )
      : control_points_( control_points )
   {}
   // ...
private:
   const int control_points_;
};

namespace constant
{
   const int spline_control_points = 8;
}
class Config
{
public:
   Config();
   void readFile( std::string const & file );

   // returns the configured value for SplineControlPoints or
   // constant::spline_control_points if the option does not 
   // appear in config.
   int getSplineControlPoints() const;
};

int main()
{
   Config config;
   config.readFile( "~/.configuration" ); // read config

   Curve c( config.getSplineControlPoints() );
}

Por tipo integral Estou normalmete usando:

class Curve
{
   public:
      enum 
      {
          CONTROL_POINT_COUNT = 8
      };
};

Se constante não precisa de quaisquer entidades, exceto implementação de classe I declarar constantes em arquivo .cpp *.

namespace
{
const int CONTROL_POINT_COUNT = 8;
}

Em geral, todos os seus dados deve ser privado e acessados ??através de getters e setters. Caso contrário, você violar o encapsulamento. Ou seja, se você expor os dados subjacentes você se tranca e sua classe em uma representação particular de que os dados subjacentes.

Neste caso específico, eu teria feito a algo como o seguinte eu penso:

class Curve
{

   protected:

      int getControlPointCount() {return _controlPointCount;}
      int setControlPointCount(int c) { _controlPointCount = c; }

   private:

      static int _controlPointCount = 0;
};

Constantes em geral não deve ser definido dentro de métodos. O exemplo que você está escolhendo tem duas características únicas. Primeiro, é um getter; em segundo lugar, o tipo a ser devolvido é um int. Mas o ponto de constantes que definem é usá-los mais de uma vez, e para ser capaz de se referir a eles de uma forma conveniente. Typing "8" em oposição a "controlPointCount" pode poupar tempo e pode não parecer a incorrer em um custo de manutenção, mas isso não será tipicamente verdadeiro se você sempre definir constantes dentro de métodos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top