2010-10-18 5 views
3

J'ai une classe qui prend de nombreux arguments à créer. C'est une sorte de processeur audio qui a besoin d'une fréquence d'échantillonnage, d'une résolution d'échantillonnage, d'un nombre de canaux, etc. La plupart des paramètres ont des valeurs par défaut saines. Et la plupart d'entre eux ne devraient être configurables que dans l'initialiseur (constructeur), car cela n'a aucun sens de les changer par la suite. Je ne veux pas créer un initialiseur gargantuesque avec tous les paramètres car (1) ce serait énorme et essentiellement il ne ferait que copier les valeurs passées, ne faisant aucun travail réel, et (2) l'utilisateur devrait spécifier des valeurs pour tous les paramètres. Quel est un bon moyen de résoudre cela?Comment initialiser une classe avec de nombreux arguments constructeur?

J'ai essayé d'écrire des getters et des setters pour les params. Cela signifie que je ne pouvais pas créer la "vraie" unité de traitement audio dans le constructeur, puisque les valeurs des paramètres ne sont pas connues à ce moment-là. Je devais introduire une nouvelle méthode (par exemple prepareForWork) afin que les utilisateurs peuvent faire quelque chose comme:

AudioProcessor *box = [[AudioProcessor alloc] init]; 
[box setSampleRate:…]; 
[box setNumberOfChannels:…]; 
[box prepareForWork]; 
[box doSomeProcessing]; 

C'est agréable car il ne nécessite pas de constructeur difficile à manier. De plus, les valeurs par défaut sont définies dans l'initialiseur, ce qui signifie que je peux prendre une nouvelle instance AudioProcessor et il pourrait encore faire un peu de travail. Le revers de la médaille est que (1) il y a une méthode supplémentaire qui doit être appelée avant que l'instance puisse faire un travail réel et (2) la classe devrait refuser de changer l'un des paramètres après que prepareForWork ait été appelée. Garder ces deux invariants prendrait un code standard que je n'aime pas.

Je pensais que je pouvais créer une classe spéciale « preset » qui ressemblerait à ceci:

@interface SoundConfig : NSObject { 
    NSUInteger numberOfChannels; 
    NSUInteger sampleResolution; 
    float sampleRate; 
} 

Et puis besoin d'une instance de cette classe dans le AudioProcessor initialiseur:

@interface AudioProcessor : NSObject {…} 
- (id) initWithConfig: (SoundConfig*) config; 

Les valeurs par défaut serait défini dans l'initialiseur SoundConfig, le constructeur AudioProcessor serait simple et il n'y aurait pas d'invariants à continuer à regarder à la main.

Une autre approche que je pensais était une sorte de classe AudioProcessorBuilder. Vous créez une instance de ceci, définissez les paramètres audio à travers les accesseurs et enfin, vous construisez une instance AudioProcessor pour vous, définissant toutes les propriétés via un setters non public de sorte que vous ne puissiez pas les changer plus tard (et rompez l'invariant) .

Maintenant que j'écris cela, je suis favorable à l'approche SoundConfig. Comment résolvez-vous cela, y a-t-il une meilleure approche?

Répondre

4

Voir comment NSURLConnection est implémenté et used. Il utilise un objet NSURLRequest pour le paramétrer, de la même manière que votre objet SoundConfig paramètre l'objet AudioProcessor.

+0

Aurait été bien si vous pouviez un exemple d'utilisation.Le lien fourni n'est plus disponible. –

1

Habituellement, lorsque vous avez une classe avec de nombreux paramètres constructeurs, en particulier lorsque certains ou la plupart d'entre eux sont facultatifs, vous voulez utiliser Builder Pattern. Chose drôle, je ne trouve pas d'exemples pour l'objectif-c, donc je ne suis pas sûr si elle pourrait être facilement appliquée ici ...

2

La façon habituelle est en effet de créer un initialiseur gargantuesque avec plusieurs initialiseurs pour des valeurs non par défaut ou ensembles de valeurs.

-initWithSampleRate:numberOfChannels:sampleResolution: 
-initWithSampleRate:sampleResolution: 
-initWithSampleRate:numberOfChannels: 
-initWithNumberOfChannels:sampleResolution: 
-initWithNumberOfChannels: 
-initWithSampleResolution: 
-initWithSampleRate: 
-init 

Mais l'approche SoundConfig semble plus simple.

+1

Si vous optez pour l'option SoundConfig, que je suis d'accord, vous aimerez mieux, pensez plutôt à utiliser NSDictionary. NSDictionary semble être la façon d'Apple d'initialiser des objets avec un grand nombre de paramètres arbitraires. – JeremyP

+0

Le dictionnaire est sympa car il n'ajoute pas d'autre classe supplémentaire, mais je ne peux pas penser à un moyen vraiment simple d'ajouter des valeurs par défaut, et la boxe est très chiante. – zoul

Questions connexes