27 votes

quel (s) modèle (s) de conception GOF a une implémentation entièrement différente (java vs Scala)

Récemment, j'ai lu la suite DONC, la question :

Est-il un cas d'utilisation pour l'employant le Modèle Visiteur dans Scala? Dois-je utiliser le Pattern Matching in Scala à chaque fois que je l'aurais utilisé le Modèle Visiteur en Java?

Le lien de la question avec le titre: Modèle visiteur en Scala. L'on a accepté la réponse commence par la

Oui, vous devriez probablement commencer avec la correspondance de modèle au lieu de le modèle visiteur. Voir ce http://www.artima.com/scalazine/articles/pattern_matching.html

Ma question (inspiré par au-dessus de la question) est ce qui GOF modèle de Conception(s) est tout à fait différente de la mise en œuvre de Scala? Où dois-je être prudent et de ne pas suivre java modèle de programmation basé sur des Modèles de Conception (Gang of four), si je suis la programmation Scala?

Creational modèles

  • Résumé De L'Usine
  • Constructeur
  • Méthode De Fabrique
  • Prototype
  • Singleton : créer Directement un Objet (la scala)

Les modèles structurels

  • Adaptateur
  • Pont
  • Composite
  • Décorateur
  • Façade
  • Poids mouche
  • Proxy

Les modèles de comportement

  • La chaîne de responsabilité
  • Commande
  • Interprète
  • Itérateur
  • Médiateur
  • Memento
  • Observateur
  • État
  • Stratégie
  • Méthode de modèle
  • Visiteur : Patten Correspondance (scala)

33voto

Rex Kerr Points 94401

Pour presque tous ces cas, il y a Scala solutions alternatives certains mais pas tous les cas d'utilisation de ces modèles. Tout cela est de l'OMI, bien sûr, mais:

Creational Modèles

Constructeur

Scala peut le faire plus élégamment avec les types génériques que peut Java, mais l'idée générale est la même. En Scala, le modèle le plus simplement mis en œuvre comme suit:

trait Status
trait Done extends Status
trait Need extends Status

case class Built(a: Int, b: String) {}
class Builder[A <: Status, B <: Status] private () {
  private var built = Built(0,"")
  def setA(a0: Int) = { built = built.copy(a = a0); this.asInstanceOf[Builder[Done,B]] }
  def setB(b0: String) = { built = built.copy(b = b0); this.asInstanceOf[Builder[A,Done]] }
  def result(implicit ev: Builder[A,B] <:< Builder[Done,Done]) = built
}
object Builder {
  def apply() = new Builder[Need, Need]
}

(Si vous essayez ceci dans le REPL, assurez-vous que la classe et l'objet Builder sont définies dans le même bloc, c'est à dire utiliser :paste.) La combinaison de la vérification des types avec <:<, type générique arguments, et la méthode de copie des classes de cas de faire une très puissante combinaison.

Méthode de fabrique (et Abstraite de l'Usine de la Méthode)

Méthodes de fabrique' utilisation principale est de garder vos types de droit; sinon, vous pouvez aussi bien utiliser des constructeurs. Avec Scala, le puissant système de type, vous n'avez pas besoin d'aide pour garder vos types de droit, de sorte que vous pourriez aussi bien utiliser le constructeur ou un apply méthode dans le compagnon objet de votre classe et de créer des choses de cette façon. Dans le compagnon de l'objet-cas en particulier, il n'est pas plus difficile de garder cette interface cohérente que c'est pour garder l'interface de l'usine, objet conforme. Ainsi, la plupart de la motivation pour les objets de fabrique est allé.

De même, de nombreux cas de résumé de méthodes de fabrique peut être remplacée par avoir un compagnon objet hérite d'un trait.

Prototype

Bien sûr méthodes de remplacement et du genre, ont leur place dans la Scala. Cependant, les exemples utilisés pour le Prototype de modèle sur les Modèles de Conception de site web sont plutôt déconseillée en Scala (ou Java OMI). Cependant, si vous souhaitez avoir une super-classe de sélectionner les actions basées sur ses sous-classes plutôt que de les laisser décider pour eux-mêmes, vous devez utiliser match plutôt que le maladroit instanceof tests.

Singleton

Scala embrasse avec object. Ils sont des singletons--l'utiliser et en profiter!

Les Modèles Structurels

Adaptateur

Scala trait offre beaucoup plus de puissance, ici, plutôt que de créer une classe qui implémente une interface, par exemple, vous pouvez créer un trait qui implémente seulement une partie de l'interface, laissant le reste pour vous à définir. Par exemple, java.awt.event.MouseMotionListener vous oblige à remplir deux méthodes:

def mouseDragged(me: java.awt.event.MouseEvent)
def mouseMoved(me: java.awt.event.MouseEvent)

Peut-être que vous voulez ignorer les faisant glisser. Ensuite, vous écrivez un trait:

trait MouseMoveListener extends java.awt.event.MouseMotionListener {
  def mouseDragged(me: java.awt.event.MouseEvent) {}
}

Maintenant, vous pouvez mettre en œuvre seulement mouseMoved lorsque vous héritez de cette. Donc: modèle similaire, mais beaucoup plus de puissance avec Scala.

Pont

Vous pouvez écrire des ponts en Scala. C'est une énorme quantité de passe-partout, mais pas tout à fait aussi mauvais que dans Java. Je ne recommande pas systématiquement l'aide de cette méthode de l'abstraction; pensez à vos interfaces soigneusement d'abord. Gardez à l'esprit que, avec l'augmentation de la puissance de traits de caractère que vous pouvez souvent utiliser ceux de simplifier une interface plus élaborée dans un endroit où vous pourriez être tenté d'écrire un pont.

Dans certains cas, vous pouvez écrire une interface transformateur au lieu de Java pont de modèle. Par exemple, vous voulez peut-être traiter les dragues et les mouvements de la souris en utilisant la même interface avec seulement un indicateur booléen de les distinguer. Ensuite, vous pouvez

trait MouseMotioner extends java.awt.event.MouseMotionListener {
  def mouseMotion(me: java.awt.event.MouseEvent, drag: Boolean): Unit
  def mouseMoved(me: java.awt.event.MouseEvent) { mouseMotion(me, false) }
  def mouseDragged(me: java.awt.event.MouseEvent) { mouseDragged(me, true) }
}

Cela vous permet de sauter la majorité du pont modèle passe-partout, tandis que la réalisation d'un degré élevé de mise en œuvre de l'indépendance et de laisser vos classes d'obéir à l'interface d'origine (si vous n'avez pas à garder l'emballage et déballage de mer).

Composite

Le diagramme composite est particulièrement facile à réaliser avec des classes de cas, bien que faisant des mises à jour est plutôt ardu. Il est également précieux dans Scala et Java.

Décorateur

Les décorateurs sont difficiles. D'habitude vous ne souhaitez pas utiliser les mêmes méthodes sur une autre classe dans le cas où l'héritage n'est pas exactement ce que vous voulez, ce que vous voulez vraiment est une autre méthode de la même classe qui fait ce que vous voulez au lieu de la valeur par défaut de la chose. L' enrichir ma bibliothèque de modèle est souvent un supérieur de substitution.

Façade

Façade fonctionne mieux dans le Scala qu'en Java, car vous pouvez avoir des traits réaliser partielle implémentations autour de sorte que vous n'avez pas à faire tout le travail vous-même lorsque vous les combinez.

Poids mouche

Bien que le poids mouche idée est aussi valable en Scala, Java, vous avez un couple de plus à votre disposition des outils pour la mettre en œuvre: lazy val, d'où une variable n'est pas créé, sauf si c'est vraiment nécessaire (et, par la suite, est réutilisé), et by-name parameters, où vous seulement faire le travail nécessaire à la création d'un argument de fonction si la fonction utilise cette valeur. Cela dit, dans certains cas, la Java modèle est inchangé.

Proxy

Fonctionne de la même manière dans Scala comme Java.

Les Modèles De Comportement

La chaîne de responsabilité

Dans les cas où vous pouvez lister les parties responsables dans l'ordre, vous pouvez

xs.find(_.handleMessage(m))

en supposant que tout le monde a un handleMessage méthode qui retourne true si le message a été traité. Si vous souhaitez muter le message comme il va, utiliser un pli à la place.

Depuis, il est facile de déposer les parties responsables en Buffer de la sorte, l'élaboration du cadre utilisé dans les solutions Java a rarement une place en Scala.

Commande

Ce modèle est presque entièrement remplacée par des fonctions. Par exemple, au lieu de tout

public interface ChangeListener extends EventListener {
  void stateChanged(ChangeEvent e)
}
...
void addChangeListener(ChangeListener listener) { ... }

il vous suffit de

def onChange(f: ChangeEvent => Unit)

Interprète

Scala offre analyseur combinators qui sont considérablement plus puissant que le simple interprète proposé comme un Modèle de Conception.

Itérateur

Scala a Iterator dans sa bibliothèque standard. Il est presque banal de faire votre propre classe d'étendre Iterator ou Iterable; ce dernier est généralement préférable car elle permet de réutiliser trivial. Certainement une bonne idée, mais si simple, j'ai peine à appeler ça un motif.

Médiateur

Cela fonctionne bien en Scala, mais est généralement utile pour mutable données, et même les médiateurs peuvent tomber à l'encontre des conditions de course et ces si pas utilisé avec précaution. Au lieu de cela, essayez si possible d'avoir vos données tous stockés dans un immuable de la collecte, de la classe de cas, ou que ce soit, et, lors d'une mise à jour qui nécessite des changements coordonnés, changement de toutes les choses en même temps. Ce ne sera pas vous aider à l'interface avec d' javax.swing, mais est par ailleurs largement applicable:

case class Entry(s: String, d: Double, notes: Option[String]) {}

def parse(s0: String, old: Entry) = {
  try { old.copy(s = s0, d = s0.toDouble) }
  catch { case e: Exception => old }
}

Enregistrer le médiateur modèle pour quand vous avez besoin de gérer de multiples relations différentes (un médiateur pour chacun), ou lorsque vous avez des données mutable.

Memento

lazy val est presque idéale pour de nombreuses applications les plus simples de la memento motif, par exemple

class OneRandom {
  lazy val value = scala.util.Random.nextInt
}
val r = new OneRandom
r.value  // Evaluated here
r.value  // Same value returned again

Vous pouvez créer une petite classe spécifiquement pour les paresseux de l'évaluation:

class Lazily[A](a: => A) {
  lazy val value = a
}
val r = Lazily(scala.util.Random.nextInt)
// not actually called until/unless we ask for r.value

Observateur

C'est un fragile de motif au mieux. Favoriser, chaque fois que possible, garder immuable de l'état (voir le Médiateur), ou en utilisant les acteurs, où un acteur envoie des messages à tous les autres concernant le changement d'état, mais où chaque acteur peut supporter d'être hors de date.

État

Ceci est également utile dans la Scala, et est en fait la meilleure façon de créer des énumérations lorsqu'il est appliqué à methodless traits:

sealed trait DayOfWeek
final trait Sunday extends DayOfWeek
...
final trait Saturday extends DayOfWeek

(fréquence vous souhaitez les jours de la semaine pour faire quelque chose pour justifier ce montant réutilisable).

Stratégie

C'est presque entièrement remplacé par des méthodes prennent des fonctions qui mettent en œuvre une stratégie, et de fournir des fonctions de choisir à partir.

def printElapsedTime(t: Long, rounding: Double => Long = math.round) {
  println(rounding(t*0.001))
}
printElapsedTime(1700, math.floor)  // Change strategy

Méthode De Modèle

Les Traits offrent beaucoup plus de possibilités là que, il est préférable de considérer un autre motif. Vous pouvez remplir autant de code que vous pouvez à partir d'autant d'informations que vous avez à votre niveau d'abstraction. Je ne voudrais vraiment appeler ça de la même chose.

Visiteur

Entre structurels de frappe et de la conversion implicite, Scala a étonnamment plus de capacités que Java est typique des habitudes des visiteurs. Il n'y a pas de point à l'aide du modèle original; vous aurez juste se laisser distraire de la bonne façon de le faire. De nombreux exemples sont vraiment juste qui souhaitent y avait une fonction définie sur la chose qu'il soit visité, qui Scala peut faire pour vous trivialement (c'est à dire convertir une méthode arbitraire à une fonction).

9voto

Daniel C. Sobral Points 159554

Ok, nous allons jeter un bref coup d'oeil à ces modèles. Je suis à la recherche de tous ces modèles purement fonctionnels point de vue programmation, et laissant de côté beaucoup de choses que la Scala peuvent s'améliorer à partir d'un OO point de vue. Rex Kerr réponse fournit un intéressant contre-point à mes propres réponses (je n'ai lu que sa réponse après avoir écrit mon propre).

Avec cela à l'esprit, je tiens à dire qu'il est important d'étudier persistante des structures de données (fonctionnellement pur structures de données) et les monades. Si vous voulez aller plus loin, je pense que la catégorie de la théorie de base sont importants: la catégorie la théorie ne peut décrire formellement toutes les structures de programmes, y compris impératif ceux.

Creational Modèles

Un constructeur n'est rien de plus qu'une fonction. Un constructeur sans paramètre de type T n'est rien de plus qu'une fonction () => T, par exemple. En fait, Scala du sucre syntaxique pour les fonctions est pris parti sur le cas de classes:

case class T(x: Int)

C'est l'équivalent de:

class T(val x: Int) { /* bunch of methods */ }
object T {
  def apply(x: Int) = new T(x)
  /* other stuff */
}

De sorte que vous pouvez instancier T avec T(n) au lieu de new T(n). Vous pouvez même écrire comme ceci:

object T extends Int => T {
  def apply(x: Int) = new T(x)
  /* other stuff */
}

Qui se transforme T dans une fonction formelle, sans modification de code.

C'est le point important à garder à l'esprit lorsque l'on pense de creational modèles. Donc, nous allons regarder:

Résumé De L'Usine

Celui-ci est peu susceptible de changer beaucoup. Une classe peut être considérée comme un groupe étroitement lié fonctions, de sorte qu'un groupe de étroitement liées l'une des fonctions est facilement mis en œuvre à travers une classe, qui est ce que ce modèle n'est pour les constructeurs.

Constructeur

Constructeur modèles peuvent être remplacées par des fonctions curryfiées ou partielle en fonction des applications.

def makeCar: Size => Engine => Luxuries => Car = ???
def makeLargeCars = makeCar(Size.Large) _

def makeCar: (Size, Engine, Luxuries) => Car = ???
def makeLargeCars = makeCar(Size.Large, _: Engine, _: Luxuries)

Méthode De Fabrique

Devient obsolète si vous jetez sous-classement.

Prototype

Ne change pas, en fait, c'est une façon commune de la création de données fonctionnelle des structures de données. Voir des classes de cas copy méthode, ou tous les non-mutable méthodes sur les collections de retour des collections.

Singleton

Les Singletons sont pas particulièrement utile lors de vos données est immuable, mais Scala object met en œuvre ce modèle est une manière sûre.

Les Modèles Structurels

Cela est principalement dû à des structures de données, et le point le plus important sur la programmation fonctionnelle, c'est que les structures de données sont généralement immuable. Vous feriez mieux de regarder la persistance des structures de données, les monades et les concepts connexes que d'essayer de traduire ces modèles.

Non pas que certains modèles ne sont pas pertinentes. Je dis juste que, en règle générale, vous devriez regarder dans les choses d'en haut au lieu d'essayer de traduire les modèles structurels en équivalents fonctionnels.

Adaptateur

Cette tendance est liée à des classes (nominale de frappe), donc il reste important aussi longtemps que vous avez, et n'est pas pertinent quand vous n'en avez pas.

Pont

Liés à l'architecture OO, donc, le même que ci-dessus.

Composite

Beaucoup de Verres et de Fermetures à glissière.

Décorateur

Un Décorateur est juste en fonction de la composition. Si vous êtes à la décoration de l'ensemble de la classe, qui peut ne pas s'appliquer. Mais si vous donnez des fonctionnalités comme des fonctions, puis de composer une fonction tout en conservant son type est un décorateur.

Façade

Même commentaire que pour le Pont.

Poids mouche

Si vous pensez que des constructeurs comme des fonctions, pense de la catégorie poids mouche en fonction memoization. Aussi, le poids Mouche est intrinsèque liée à la façon dont les données persistantes les structures sont construites, et les avantages d'un lot de l'immuabilité.

Proxy

Même commentaire que pour la Carte.

Les Modèles De Comportement

C'est toute la place. Certains d'entre eux sont complètement inutiles, alors que d'autres sont aussi pertinents comme toujours dans un paramètre fonctionnel.

La chaîne de Responsabilité

Comme Décorateur, c'est fonction de la composition.

Commande

C'est une fonction. L'annulation d'une partie n'est pas nécessaire si vos données est immuable. Sinon, il suffit de garder une paire de fonction et son inverse. Voir aussi des Lentilles.

Interprète

C'est une monade.

Itérateur

Il peut être rendu obsolète par juste de passage d'une fonction à la collection. C'est ce qu' Traversable avec foreach, en fait. Aussi, voir Iteratee.

Médiateur

Toujours pertinent.

Memento

Inutile avec des objets immuables. Aussi, son point est de garder l'encapsulation, qui n'est pas une préoccupation majeure dans la FP.

Notez que ce modèle n'est pas la sérialisation, qui est toujours d'actualité.

Observateur

Pertinent, mais voir Fonctionnel Réactif de Programmation.

État

C'est une monade.

Stratégie

Une stratégie est une fonction.

Méthode De Modèle

C'est un modèle de conception OO, il est donc pertinent pour OO dessins.

Visiteur

Un visiteur est juste une méthode de la réception d'une fonction. En fait, c'est ce qu' Traversables' foreach n'.

En Scala, il peut également être remplacé par des extracteurs.

2voto

mishadoff Points 6034

Je suppose que, Command modèle ne sont pas nécessaires dans les langages fonctionnels à tous. Au lieu de l'encapsulation de commande de fonction à l'intérieur de l'objet, puis en sélectionnant approprié à l'objet, il suffit d'utiliser la fonction appropriée lui-même.

Flyweight est juste le cache, et a défaut de mise en œuvre dans la plupart des langages fonctionnels (memoize en clojure)

Même Template method, Strategy et State peut être mis en œuvre avec juste de passage de la fonction appropriée dans la méthode.

Donc, je recommande de ne pas aller en profondeur dans les Modèles de Conception lorsque vous tente de vous-même dans le style fonctionnel mais la lecture de quelques livres sur le sujet, les concepts de fonctions (les fonctions, de la paresse, de nourrissage, et ainsi de suite)

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