Come affrontare l'estensibilità considerando l'Anti-Simmetria Dati / Oggetto?

6

In Clean Code di Uncle Bob, pagina 124-125 afferma

Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.

Sto leggendo su Multiple Dispatches come in questo articolo su più spedizioni e chiedendosi se risolve il problema.

Jörg W Mittag dice che questo è stato definito come Problema di espressione di Phil Wadler , ma afferma che per risolvere il problema dovremmo

define a datatype by cases, where one can add new cases to the datatype and new functions over the datatype, without recompiling existing code, and while retaining static type safety [...]

Sono più interessato all'estensibilità di un software, ad esempio se è "facile" aggiungere nuove funzionalità in modo incrementale. In questo caso, ho una definizione intuitiva di "facile" e include resistenza agli errori e nessun codice duplicato.

Ecco gli esempi di Uncle Bob dal libro

Forme polimorfiche

public class Square implements Shape {
 private Point topLeft;
 private double side;

 public double area() {
  return side * side;
 }
}

public class Rectangle implements Shape {
 private Point topLeft;
 private double height;
 private double width;

 public double area() {
  return height * width;
 }
}

public class Circle implements Shape {
 private Point center;
 private double radius;
 public final double PI = 3.141592653589793;

 public double area() {
  return PI * radius * radius;
 }
}

Forma procedurale

public class Square {
 public Point topLeft;
 public double side;
}

public class Rectangle {
 public Point topLeft;
 public double height;
 public double width;
}

public class Circle {
 public Point center;
 public double radius;
}

public class Geometry {
 public final double PI = 3.141592653589793;

 public double area(Object shape) throws NoSuchShapeException {
  if (shape instanceof Square) {
   Square s = (Square) shape;
   return s.side * s.side;
  } 

  else if (shape instanceof Rectangle) {
   Rectangle r = (Rectangle) shape;
   return r.height * r.width;
  } 
  else if (shape instanceof Circle) {
   Circle c = (Circle) shape;
   return PI * c.radius * c.radius;
  }
  throw new NoSuchShapeException();
 }
}
    
posta Jp_ 27.04.2018 - 19:40
fonte

1 risposta

8

Questo è stato definito il Problema di espressione di Phil Wadler, anche se è molto più vecchio della discussione in cui è uscito con questo termine. Risolvendolo è uno dei "sacri graal" di Programming Language Design.

Uno dei problemi con qualcosa di così famoso è che tutti escono con le loro definizioni, quindi parlarne, senza definirlo rigorosamente, ha poco senso, se non per invitare flamewar.

Phil Wadler aveva questi quattro vincoli:

  1. Estendi il codice con nuove operazioni sui tipi di dati esistenti.
  2. Estendi il codice con nuovi tipi di dati che funzionano con le operazioni esistenti.
  3. Questa dovrebbe essere l'estensione true , cioè nessuna modifica del codice esistente.
  4. Dovrebbe essere staticamente sicuro dal tipo.

Le classi aperte mutabili in stile rubino con i prototipi mutabili in stile Monkeypatching o ECMAScript risolvono i problemi 1 e 2. Possiamo discutere se risolvono veramente il punto 3, tuttavia: se metti una classe in memoria , ma il codice che esegue questa mutazione si trova in un file separato ... è l'estensione o la modifica del codice esistente?

Quindi, diciamo, risolvono 2.5 dei problemi, ma ovviamente non sono staticamente sicuri per il tipo.

I multimetodi in stile CLOS risolvono 3 completamente, ma falliscono ancora a 4. Penso che sia i multimetodi MultiJava che quelli Tuple Class possano qualificarsi, ma non li conosco troppo bene.

I Typeclasses di Haskell sono stati il primo sistema a soddisfare tutti e 4 i vincoli.

Martin Odersky et al. aggiunto altri due vincoli:

  1. Dovrebbe essere modulare, cioè l'estensione dovrebbe essere in un modulo separato (nel senso PLT della parola) che viene distribuito separatamente.
  2. E questo include il controllo ortografico modulare

Haskell Typeclasses fallisce effettivamente al # 6. Scala i valori impliciti e le conversioni implicite, tuttavia fa risolve tutti e 6 i problemi.

Nota: ci sono altre funzionalità in Haskell che risolvono tutte e 6, ma non ho molta familiarità con tutte le estensioni e ricerche che sono state fatte da Typeclasses.

Per rispondere alla tua domanda attuale:

I'm reading about Multiple Dispatches like in this article and wondering if it solves the problem

Indipendentemente dal fatto che Multiple Dispatch risolva il problema dipende da come si definisce "risolva" e da cosa si considera "il problema".

    
risposta data 28.04.2018 - 02:01
fonte