42 votes

Réduire le nombre d'arguments à un constructeur

Je suis à la lecture de "Code Propre" et de la difficulté à trouver comment garder certains de mes fonctions (constructeurs) à leur MAXIMUM de 3 paramètres.

Souvent, mes objets en besoin d'une énorme quantité d'informations, de travail - suis-je censé faire un petit constructeur et ensuite utiliser mutateur fonctions de leur donner toutes les informations? Ce n'est pas tout l'air d'être mieux que de simplement à l'aide d'un grand constructeur.

Comme un exemple, j'ai un "MovablePatch" de la classe. Il permet à l'utilisateur de faire glisser un carré autour de dans une fenêtre. Il a besoin d'un plusieurs paramètres, y compris le Rayon, la Couleur, le moteur de Rendu, InitialPosition, et de la Visibilité. Actuellement j'ai l'recueillir toutes à partir de mon interface graphique, puis composez le:

MovablePatch(int radius, Renderer* renderer, Color color,  Position initial, bool visibility)

Ce n'est que certaines des choses que j'ai besoin dans cette classe. Quelqu'un peut-il suggérer comment je pourrais paquet de cette information à passer au constructeur? Je ne vois pas du tout évident "diviser en plus petites classes" que l'on voit ici.

31voto

Adam Dymitruk Points 34999

Vous pourriez avoir

MovablePatch(Renderer* renderer, CircleAppearance circleAppearance)

où CircleAppearance rassemble les autres infos.

Toutefois, le code propre et d'autres livres que des généralisations au sujet de ce que le bon code devrait ressembler, se sont fixé pour objectif de 80 pour cent du code là-bas. Votre code semble être "plus proche du métal" que le LoB (Line of Business) de la variété. En tant que tel, vous pouvez courir dans des endroits où certains de codage idéaux ne sont pas applicables.

La partie la plus importante est que vous êtes en train de penser à ce sujet et d'essayer de garder de belles choses et bien rangé! :)

29voto

Mike Nakis Points 7259

Ne prenez pas de maximes comme "tu ne dois pas avoir plus de 3 paramètres dans ton constructeurs" à la valeur nominale. Si vous avez la moindre chance de faire un objet immuable, le faire; et s'étant immuable signifie qu'il va avoir un constructeur avec 50 paramètres, ainsi soit-il; allez-y; ne pensez même pas à deux fois.

Même si l'objet va être mutable, encore, vous devez passer par son constructeur comme beaucoup de paramètres que nécessaire, de sorte que immédiatement après la construction, il sera valide et significative de l'état. Dans mon livre, il est absolument inadmissible d'avoir à savoir qui sont les magic mutateur méthodes qui doivent être appelés (parfois même dans le bon ordre) avant toutes les autres méthodes peuvent être invoquées, sous peine d'erreur de segmentation.

Ceci étant dit, si vous voulez vraiment réduire le nombre de paramètres à un constructeur, ou à n'importe quelle fonction, il suffit de passer cette méthode d'une interface qu'il peut invoquer pour obtenir de lui les choses dont il a besoin pour travailler.

21voto

Donald Miner Points 18116

Certaines des choses que vous êtes de passage dans la pourrait être prélevée dans une plus grande structure. Par exemple, visibility, color, et radius, pourrait avoir un sens pour être placé dans un objet que vous définissez. Ensuite, une instance de cette classe, appelons ColoredCircle, pourrait être passé dans le constructeur de l' MovablePatch. Un ColoredCircle ne se soucie pas où il est ni ce moteur de rendu il est utilisé, mais un MovablePatch n'.

Mon point principal, c'est qu'à partir d'un OO point de vue, radius n'est pas vraiment un entier, c'est un rayon. Vous voulez éviter ces longues constructeur de listes, car il est difficile de comprendre le contexte de ces choses. Si vous les recueillir dans une classe plus large, un peu comme la façon dont vous avez déjà avec Color et Position, vous pouvez avoir moins de paramètres passé en et de le rendre plus facile à comprendre.

12voto

Sam Miller Points 14976

Le Paramètre Nommé Idiome est utile ici. Dans votre cas, vous pouvez avoir

class PatchBuilder
{
public:
    PatchBuilder() { }
    PatchBuilder& radius(int r) { _radius = r; return *this; }
    PatchBuilder& renderer(Renderer* r) { _renderer = r; return *this; }
    PatchBuilder& color(const Color& c) { _color = c; return *this; }
    PatchBuilder& initial(const Position& p) { _position = p; return *this; }
    PatchBuilder& visibility(bool v) { _visibility = v; return *this; }

private:
    friend class MovablePatch;
    int _radius;
    Renderer* _renderer;
    Color _color;
    Position _position;
    bool _visibility;
};

class MovablePatch
{
public:
    MovablePatch( const PatchBuilder& b ) :
        _radius( b._radius );
        _renderer( b._renderer );
        _color( b._color );
        _position( b._position );
        _visibility( b._visibility );
    {

    }

private:
    int _radius;
    Renderer* _renderer;
    Color _color;
    Position _position;
    bool _visibility;
};

ensuite, vous l'utilisez comme une sorte

int
main()
{
    MovablePatch foo = PatchBuilder().
        radius( 1.3 ).
        renderer( asdf ).
        color( asdf ).
        position( asdf ).
        visibility( true )
     ;
}

trop simplifié, mais je pense qu'il obtient le point à travers. Si certains paramètres sont nécessaires, elles peuvent être incluses dans l' PatchBuilder constructeur de:

class PatchBuilder
{
public:
    PatchBuilder(const Foo& required) : _foo(required) { }
    ...
};

Évidemment, ce modèle dégénère dans le problème original si tous les arguments sont tenus, dans ce cas le paramètre nommé idiome n'est pas applicable. Le point de l'être, ce n'est pas une solution unique pour tous, et comme Adam décrit dans le commentaire ci-dessous il y a des coûts supplémentaires et des frais généraux avec le faire.

8voto

Beccari Points 326

Une bonne option consiste à utiliser un modèle Builder, dans lequel chaque méthode "setter" renvoie la propre instance, et vous pouvez chaîner les méthodes selon vos besoins.

Dans votre cas, vous obtiendrez une nouvelle classe MovablePatchBuilder .

Cette approche est très utile et vous pouvez la trouver dans de nombreux cadres et langages différents.

Reportez-vous ici pour voir quelques exemples.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X