Modèle de conception du GoF à partir du problème 2. Structure

C'est la structure de la série de modèles de conception du GoF du point de vue des problèmes.

  1. Generation
  2. Structure
  3. Comportement

: question: je souhaite que la réponse de l'API soit adaptée au domaine

before

FooAPI fooAPI = new FooAPI(lat, lng);
FooPlace place = new FooPlace();
place.setAddress(fooAPI.getPostalCode() + " " + fooAPI.getAddress()); // 〒012-3456 Hoge City, Préfecture de Hoge
place.setStation(
  new StringJoiner(",")
    .add(fooAPI.getStation1())
    .add(fooAPI.getStation2())
    .add(fooAPI.getStation3())
    .toString());  //Cette station,Gare de Kakiku,Gare de Sashisu

C'est un cas où le résultat de l'API est formaté et utilisé. C'est le seul endroit où le FooAPI est utilisé, et si la méthode de mise en forme ne change pas à l'avenir, c'est bien, mais compte tenu de la maintenabilité, ce n'est pas une bonne conception.

after :bulb: Adapter

public class FooAPIAdapter {

  private final FooAPI fooAPI;

  public FooAPIAdapter(double latitude, double longitude) {
    this.fooAPI = new FooAPI(latitude, longitude);
  }

  public String getAddress() {
    return fooAPI.getPostalCode() + fooAPI.getAddress();
  }

  public String getStation() {
    return new StringJoiner(",")
      .add(fooAPI.getStation1())
      .add(fooAPI.getStation2())
      .add(fooAPI.getStation3())
      .toString();
  }
}
FooAPIAdapter fooAPI = new FooAPIAdapter(lat, lng);
FooPlace place = new FooPlace();
place.setAddress(fooAPI.getAddress());
place.setStation(fooAPI.getStation());

Nous avons préparé un adaptateur pour le formatage des réponses API. En cas de modification de la méthode de formatage, il vous suffit de modifier cet adaptateur et cela n'affectera pas l'utilisateur.

: question: je ne veux pas que les utilisateurs de l'API réfléchissent à l'ordre des opérations

before

public class FooSorter {

  private List<FooStudent> students = new List<>();

  public void add(FooStudent student) {
    students.add(student);
  }

  public void sort() {
    students.sort(
      Comparator.comparingInt(
        student -> student.getJapaneseScore()
          + student.getMathScore()
          + student.getEnglishScore())
      .reversed());
  }

  public List<FooStudent> getResult() {
    return students;
  }
}
FooSorter sorter = new FooSorter();
sorter.add(student1);
sorter.add(student2);
sorter.add(student3);
sorter.sort();
sorter.getResult();

Le mauvais point est que l'utilisateur doit connaître la procédure de création d'une instance → add () → sort () → getResult ().

after :bulb: Facade

public class FooSorter {

  private List<FooStudent> students = new List<>();

  private FooSorter() {}

  public static List<FooStudent> sort(FooStudent... students) {
    for (FooStudent student : students)
      add(student);

    sort();
    return getResult();
  }

  private void add(FooStudent student) {
    students.add(student);
  }

  private void sort() {
    students.sort(
      Comparator.comparingInt(
        student -> student.getJapaneseScore()
          + student.getMathScore()
          + student.getEnglishScore())
      .reversed());
  }

  private List<FooStudent> getResult() {
    return students;
  }
}
FooSorter.sort(student1, student2, student3);

L'utilisateur n'a pas à penser à la commande. À cette échelle, vous pouvez écrire sur une seule ligne, vous n'avez donc pas à séparer les méthodes en Facade, mais c'est un exemple, alors veuillez bien regarder. Facade est principalement utile pour regrouper des processus complexes qui utilisent plusieurs classes en séquence.

: question: je veux retourner le résultat de la multiplication des résultats des classes frères

before

public class FooPosition {

  private int x;
  private int y;

  // x,y accesseur

  public void moveAs(FooMove move) {
    move.move(this);
  }
}

public abstract class FooMove {

  private final int addition;

  public FooMove(int addition) {
    this.addition = addition;
  }

  public abstract void move(FooPosition position);
}

public class FooMoveHorizontal extends FooMove {

  public FooMoveHorizontal(int addition) {
    super(addition);
  }
  
  @Override
  public void move(FooPosition position) {
    position.setX(position.getX() + addition);
  }
}

public class FooMoveVertical extends FooMove {

  public FooMoveVertical(int addition) {
    super(addition);
  }

  @Override
  public void move(FooPosition position) {
    position.setY(position.getY() + addition);
  }
}
FooMove moveHorizontal = new FooMoveHorizontal(x);
FooMove moveVertical = new FooMoveVertical(y);

FooPosition position = new FooPosition();
position.moveAs(moveHorizontal);
position.moveAs(moveVertical);

C'est une conception simple et bonne en soi, mais supposons que vous souhaitiez créer une classe qui gère les mouvements dans les directions x et y en même temps. (À propos, la conception qui divise l'opération de la valeur de FooPosition en FooMove et l'accepte avec moveAs est le modèle de visiteur)

after :bulb: Decorator

public class FooPosition {

  private int x;
  private int y;

  // x,y accesseur

  public void moveAs(FooMove move) {
    move.move(this);
  }
}

public abstract class FooMove {

  private final int addition;
  private final FooMove move;

  public FooMove(int addition) {
    this.addition = addition;
  }

  public FooMove(int addition, FooMove move) {
    this.addition = addition;
    this.move = move;
  }

  public abstract void move(FooPosition position);
}

public class FooMoveHorizontal extends FooMove {

  public FooMoveHorizontal(int addition) {
    super(addition);
  }

  public FooMoveHorizontal(int addition, FooMove move) {
    super(addition, move);
  }
  
  @Override
  public void move(FooPosition position) {
    if (move != null)
      move.move(position);

    position.setX(position.getX() + addition);
  }
}

public class FooMoveVertical extends FooMove {

  public FooMoveVertical(int addition) {
    super(addition);
  }

  public FooMoveVertical(int addition, FooMove move) {
    super(addition, move);
  }

  @Override
  public void move(FooPosition position) {
    if (move != null)
      move.move(position);

    position.setY(position.getY() + addition);
  }
}
FooMove move = new FooMoveHorizontal(x, new FooMoveVertical(y));

FooPosition position = new FooPosition();
position.moveAs(move);

Les mouvements de x et y ont été résumés. De plus, avec cette conception, il vous suffit d'utiliser new FooMoveHorizontal (x, move) pour ajouter plus de mouvements. (Appelez position.moveAs une seule fois) À cette échelle, il est plus facile de comprendre si vous créez une classe qui gère x et y en même temps, mais puisqu'il s'agit d'un exemple (omis)

: question: je souhaite partager l'implémentation avec des classes frères (ou je souhaite limiter la fonction en fonction des conditions)

before

public class FooTestUser extends FooUser {

  @Override
  public void foo1() {
    //Utilisateur normal foo1
  }

  @Override
  public void foo2() {
    throw new RuntimeException("this operation is not permitted.");
  }

  @Override
  public void foo3() {
    throw new RuntimeException("this operation is not permitted.");
  }
}

public class FooNormalUser extends FooUser {

  @Override
  public void foo1() {
    //Utilisateur normal foo1
  }

  @Override
  public void foo2() {
    //Utilisateur normal foo2
  }

  @Override
  public void foo3() {
    throw new RuntimeException("this operation is not permitted.");
  }
}

public class FooSuperUser extends FooUser {

  @Override
  public void foo1() {
    //SuperUser foo1
  }

  @Override
  public void foo2() {
    //SuperUser foo2
  }

  @Override
  public void foo3() {
    //Traitement de foo3
  }
}

TestUser veut limiter ses fonctionnalités afin que seul NormalUser foo1 puisse être exécuté. À ce stade, je veux gérer que l'implémentation de foo1 de TestUser et NormalUser devienne une copie.

after :bulb: Proxy

public class FooTestUser extends FooUser {

  private FooUser normalUser = new FooNormalUser();

  @Override
  public void foo1() {
    normalUser.foo1();
  }

  @Override
  public void foo2() {
    throw new RuntimeException("this operation is not permitted.");
  }

  @Override
  public void foo3() {
    throw new RuntimeException("this operation is not permitted.");
  }
}

//L'utilisateur normal et le super utilisateur sont les mêmes qu'avant

Il n'y a pas de copier-coller de l'implémentation, et si les exigences de foo1 changent, il vous suffit de changer NormalUser. Cependant, comme Java 8 a ajouté une implémentation par défaut de l'interface, il peut être préférable que vous souhaitiez simplement partager l'implémentation. (Idem pour le modèle de pont) Si vous n'avez pas SuperUser, je pense qu'il est plus simple d'implémenter foo1 dans la classe parent (FooUser).

Recommended Posts

Modèle de conception du GoF à partir du problème 2. Structure
Modèle de conception du GoF à partir du problème 1. Génération
Modèle de conception GoF à partir du problème 3. Comportement
Résumé du modèle de conception Java GoF
Apprenez le modèle de conception "Prototype" avec Python
Apprenez le modèle de conception "Flyweight" en Python
Apprenez le modèle de conception "Memento" avec Python
Apprenez le modèle de conception "Proxy" en Python
Apprenez le modèle de conception "Commande" en Python
Apprenez le modèle de conception "Visiteur" avec Python
Apprenez le modèle de conception "Bridge" avec Python
Apprenez le modèle de conception "Mediator" avec Python
Apprenez le modèle de conception "Décorateur" avec Python
Apprenez le modèle de conception "Iterator" avec Python
Apprenez le modèle de conception «Stratégie» avec Python
Apprenez le modèle de conception "Composite" avec Python
Apprenez le modèle de conception "Singleton" avec Python
Apprenez le modèle de conception "État" en Python
Apprenez le modèle de conception "Adapter" avec Python
Apprenez le modèle de conception "Façade" avec Python
Modèle de conception #Adapter
Apprenez le modèle de conception "Abstract Factory" avec Python
Modèle de conception #Decorator
Apprenez le modèle de conception "Méthode de modèle" en Python
Modèle de conception #Observer
Apprenez le modèle de conception "Méthode d'usine" en Python
Modèle de conception #Facade
Modèle de conception #Strategy
Modèle de conception #Singleton
Modèle de conception #Proxy
Calculer le volume à partir de la structure bidimensionnelle d'un composé
Apprenez le modèle de conception «Chaîne de responsabilité» en Python
Design Pattern #Factory, méthode
Problème de conception du réseau logistique
Design Pattern #Template, méthode
À propos du modèle de visiteur
Examiner le double problème
L'histoire selon laquelle les modèles de conception du GoF ne sont rien de plus qu'une «introduction de couches abstraites»
Problème de placement d'ambulance - Tiré du numéro d'octobre du magazine OR