Question

J'ai réfléchi aux moyens de fournir du sucre syntaxique à un cadre sur lequel j'ai travaillé. Je veux traiter exclusivement avec les objets Immitables.

Disons que j’ai un objet immuable et que je souhaite en créer une version modifiée. À votre avis, une classe non instanciable avec une seule méthode d'usine statique enfreindrait-elle les principes d'OO?


  

À titre d'exemple, à l'aide d'une chaîne:

public final class LOWERCASE {

    private LOWERCASE() {}

    public static String string( final String STRING ) {

      return STRING.toLowerCase();
    }
}
     

Par conséquent, à partir de cet exemple, je pourrais écrire:

String lowercaseString = LOWERCASE.string( targetString );
     

Ce que je trouve très lisible.


Des réserves contre une telle approche?

Était-ce utile?

La solution

Je ne pense pas que ce soit une bonne idée de créer une classe par méthode. Vous pouvez à la place créer une classe de méthodes statiques, nommée par exemple StringUtils, et implémenter les méthodes. De cette façon, vous appelleriez:

Chaîne lowerCaseString = StringUtils.lowercase (targetString);

Ceci vous offrirait également une aide d’intellisense lors de la frappe. La liste de vos cours ira autrement trop grande. Même pour cet exemple simple, vous devez implémenter plusieurs classes minuscules, de manière à pouvoir également prendre en compte les circonstances dans lesquelles CulutureInfo doit être pris en compte.

Je ne pense pas que cela casse les principes d'OO ou que son design soit mauvais. Dans d'autres langues, Ruby par exemple, vous pouvez ajouter vos méthodes directement à la classe String. Méthodes qui se terminent par! indique que l'objet d'origine est modifié. Toutes les autres méthodes renvoient une copie modifiée. Le framework Ruby on Rails ajoute quelques méthodes à la classe String et il y a un débat quant à savoir si c'est une bonne technique ou non. C’est certainement pratique, cependant.

Autres conseils

Habituellement, sur les objets immuables, une méthode renverrait une version modifiée de l'objet. Ainsi, si vous avez une collection immuable, elle peut avoir une méthode sort (), qui retourne une nouvelle collection triée. Cependant, dans votre exemple String, cela n'est pas possible car vous ne pouvez pas toucher à la classe String.

Votre approche est assez lisible, et je pense que pour les cas extrêmes comme celui-ci, tout va bien. Pour les objets immuables que vous écrivez vous-même, j'aurais la méthode sur l'objet lui-même.

La série d'Eric Lippert sur les objets immuables en C # est assez bon, au fait.

À mon avis, le seul intérêt d’une classe d’usine de ce type serait que cette classe fournisse différents types d’objets immuables.

Ex:

public final class Lowercase {

  private Lowercase() {}

  public static String string( final String string ) {

   return new String( string.toLowerCase() );
  }

  public static Foo foo( final Foo f ) {
     boolean isLowerCase = true;
     return new Foo(f, isLowerCase );
  }
}

Sinon, vous devez implémenter votre méthode dans la classe immuable elle-même, comme toLowerCase () dans String Class.

Quoi qu'il en soit, je ne pense pas que cela enfreigne le principe d'OO.

Je suis d'accord avec Erik. Les objets immuables doivent toujours avoir une méthode renvoyant une version modifiée de l'objet plutôt qu'une méthode statique. Il existe également des exemples dans le JDK:

  • String.subString (int)
  • BigDecimal.movePointLeft (int)

Cette façon de procéder présente l’avantage de ne pas avoir besoin de passer l’instance que vous voulez modifier en tant qu’argument pour une méthode. Pour des classes comme String ou Integer, je préférerais utiliser une classe wrapper. Ensuite, vous pouvez contrôler quand un tel objet est créé (par le constructeur de la classe wrapper ou l’une des méthodes de la classe). Si vous utilisez la classe Integer, il est beaucoup plus compliqué de le contrôler car tout le monde peut en créer une instance.

D'autre part, votre exemple est considéré par certaines classes d'utilitaires telles que StringUtils du paquet apache commons-lang. Jetez un coup d'oeil à ceci car je pense que vous vouliez créer quelque chose comme ça. (Ne réinventez pas la roue)

new String () est une odeur de code - il est presque toujours inutile en raison de la immuabilité de String . Une fois qu'une instance String a une valeur, cette instance n'aura jamais, jamais, de valeur différente.

Dans la méthode suivante, new String () est redondant:

public static String string( final String string ) {
    return new String( string.toLowerCase() );
}

toLowerCase () renvoie une nouvelle instance (différente) String - new String () n'a aucun effet bénéfique ici que la cause. une autre création d'objet ayant la valeur exacte de l'instance String renvoyée par toLowerCase ()

Voici un petit script Groovy illustrant le concept (j'espère - remarque, il s'agit de Java sous le langage de script):

String a = 'CamelCase'
String b = a.toLowerCase()

println "a='${a}'"
println "b='${b}'"

produisant

a='CamelCase'
b='camelcase'

Notez que a n'a pas changé - il est immuable; b est une nouvelle valeur String .

Il en va de même pour BigDecimal.movePointLeft () ou toute autre méthode sur BigDecimal qui renvoie un BigDecimal - ce sont de nouvelles instances en laissant l'instance d'origine inchangée.

OK, répondez maintenant à votre question:

Avoir un ensemble d'opérations pour Strings qui remplissent une fonction utile dans votre application est une bonne idée. L'utilisation d'une fabrique n'est probablement pas nécessaire pour quelque chose comme String , mais peut-être pour une classe immuable différente qui nécessite quelques efforts de construction.

Dans le cas où il n'est pas possible d'étendre la classe de base, comme String , la classe de méthode statique décrite par @kgiannakakis est correcte.

Sinon, si le "immuable" class fait partie de l'application, où vous avez accès à la déclaration / définition de la classe, aux méthodes renvoyant une nouvelle instance, dans le modèle de BigDecimal , String , etc., serait préférable. C’est essentiellement ce que @Erik Hesselink, @ Bruno Conde et @reallyinsane ont dit.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top