web-dev-qa-db-fra.com

Comment écrire des constructeurs qui pourraient échouer correctement instancier un objet

Parfois, vous devez écrire un constructeur qui peut échouer. Par exemple, disons que je veux instancier un objet avec un chemin de fichier, quelque chose comme

obj = new Object("/home/user/foo_file")

Tant que le chemin pointe sur un fichier approprié tout va bien. Mais si la chaîne n'est pas une trajectoire valide, les choses devraient casser. Mais comment?

Vous pourriez:

  1. jeter une exception
  2. renvoyer l'objet nul (si votre langage de programmation permet aux constructeurs de renvoyer des valeurs)
  3. renvoie un objet valide mais avec un drapeau indiquant que son chemin n'était pas défini correctement (UGH)
  4. autres?

Je suppose que les "meilleures pratiques" de différentes langages de programmation mettront en œuvre cela différemment. Par exemple, je pense que Objc préfère (2). Mais (2) serait impossible à mettre en œuvre en C++ où les constructeurs doivent avoir annulé comme type de retour. Dans ce cas, je suppose que (1) est utilisé.

Dans votre langage de programmation de choix, pouvez-vous montrer comment vous géreriez ce problème et expliquer pourquoi?

11
garageàtrois

Il n'est jamais bon de compter sur un constructeur pour faire le saleté. En outre, c'est aussi non claire à un autre programmeur, que ce travail soit effectué dans le constructeur, sauf indication contraire de la documentation explicite (et que l'utilisateur de la classe l'ait lu ou a été dit. .

Par exemple (en C #):

public Sprite
{
    public Sprite(string filename)
    {
    }
}

Que se passe-t-il si l'utilisateur ne veut pas tout de suite charger le fichier? Et si elles veulent faire la mise en cache à la demande du fichier? Ils ne peuvent pas. Vous pouvez penser à mettre un argument bool loadFile dans le constructeur, mais cela rend ce désordre en désordre comme vous toujours besoin d'une méthode Load() méthode pour charger le fichier.

Compte tenu du scénario actuel, il sera plus flexible et plus clair pour les utilisateurs de la classe pour le faire:

Sprite sprite = new Sprite();
Sprite.Load("mario.png");

Ou alternativement (pour quelque chose comme une ressource):

Sprite sprite = new Sprite();
Sprite.Source = "mario.png";
Sprite.Cache();

// On demand caching of file contents.
public void Cache()
{
     if (image == null)
     {
         try
         {
             image = new Image.FromFile(Source);
         }
         catch(...)
         {
         }
     }
}
8
Nick Bedford

En Java, vous pouvez utiliser des exceptions ou utiliser le motif d'usine, ce qui vous permettrait de renvoyer NULL.

À Scala, vous pouvez retourner une option [FOO] d'une méthode d'usine. Cela fonctionnerait dans Java aussi, mais serait plus lourd.

7
Kim

Jeter une exception.

NULL doit être vérifié si vous pouvez le retourner (et ce ne sera pas vérifié)

C'est ce que fait des exceptions vérifiées. Vous savez que cela pourrait échouer. Les appelants doivent gérer cela.

3
Tim Williscroft

Dans C++, les constructeurs sont utilisés pour créer/initialiser des membres de la classe.

Il n'y a pas de bonne réponse à cette question. Mais ce que j'ai observé jusqu'à présent, c'est que la plupart du temps est le client (ou celui qui va utiliser votre API) qui choisit comment vous devez gérer ce genre de choses.

Parfois, ils pourraient vous demander d'allouer toutes les ressources que l'objet pourrait avoir besoin sur le constructeur et lancer une exception si quelque chose échoue (abandonnant la création de l'objet), ou ne fais rien de cela sur le constructeur, et Assurez-vous que la création réussira toujours, laissant ces tâches pour une fonction de membre membre à faire.

Si c'est à vous de choisir le comportement, Exceptions sont la manière C++ par défaut pour les erreurs de traitement et vous devez les utiliser quand vous le pouvez.

3
karlphillip

Vous pouvez également instancier l'objet sans paramètres ou avec uniquement des paramètres qui ne sont sûrs de ne jamais échouer, puis vous utilisez une fonction d'initialisation ou une méthode à partir de laquelle vous pouvez projeter une exception en toute sécurité ou faire ce que vous souhaitez.

1
gablin