# Oggetti e strutture

Il motivo principale per cui manteniamo le variabili private è perché non vogliamo che qualcun altro conosca i dettagli dei nostri oggetti, ma utilizzi solamente i metodi per manipolare tali dati. Allora perché creiamo variabili private se poi aggiungiamo metodi *getter* e *setter* rendendo di fatto le variabili private come se fossere pubbliche?

## Astrazione dei dati

Se creiamo oggetti con delle variabili private, dovremmo mantenere queste variabili private e fornire semplicemente dei metodi astratti che consentono di manipolare tali dati. In questo modo nascondiamo l'implementazione e forniamo solo i metodi che si occupano di manipolare l'essenza dei nostri dati.

Veicolo concreto:

```
interface Vehicle {
    public function getFuelTankCapacityInGallons(): double;
    public function getGallonsOfGasoline(): double;
}
```

Veicolo astratto:

```
interface Vehicle {
    public function getPercentFuelRemaining(): double;
}
```

In questi due esempi, il secondo è preferibile. Non vogliamo esporre i dettagli dei nostri dati. Piuttosto vogliamo esprimere i nostri dati in termini astratti.

## Asimmetria dei dati/oggetti

L'esempio sopra mostra la differenza tra **oggetti** e **strutture**. Gli **oggetti** nascondono i loro dati dietro astrazioni ed espongono le funzioni che operano su tali dati. Le **strutture** espongono i loro dati e non hanno alcuna funzione significativa.

Esempio di utilizzo delle strutture:

```
class Square {
    public $side;
}

class Rectangle {
    public $height;
    public $width;
}

class Circle {
    public $center;
    public $radius;
}

class Geometry {
    private const PI = 3.141592653589793;

    public function area(object $shape): double {
        switch(true) {
            case $shape instanceof Square:
                return pow($shape->side, 2);
            case $shape instanceof Rectangle:
                return $shape->height * $shape->width;
            case $shape instanceof Circle:
                return pow($shape->radius, 2) * self::PI;
            default:
                throw new NoSuchShapeException();
        }
    }
}
```

Esempio di utilizzo degli oggetti:

```
interface Shape {
    public function area(): double;
}

class Square implements Shape {
    private $side;

    public function __construct(double $side) {
        $this->side = $side;
    }

    public function area(): double {
        return pow($this->side, 2);
    }
}

class Rectangle implements Shape {
    private $height;
    private $width;

    public function __construct(double $height, double $width) {
        $this->height = $height;
        $this->width = $width;
    }

    public function area(): double {
        return $this->height * $this->width;
    }
}

class Circle implements Shape {
    private const PI = 3.141592653589793;
    private $center;
    private $radius;

    public function __construct(double $radius) {
        $this->radius = $radius;
    }

    public function area(): double {
        return pow($this->radius, 2) * self::PI;
    }
}
```

## In sintesi

Da questi due esempi è possibile notare la differenza sostanziale tra oggetti e strutture. Se venisse aggiunta una nuova funzione `perimeter()` alla classe `Geometry`, le classi delle forme non subirebbero nessuna modifica e l'aggiunta della nuova funzione sarebbe piuttosto semplice, ma se venisse aggiunta una nuova forma `Triangle`, dovrei andare a modificare le funzioni esistenti all'interno di `Geometry`. Al contrario, nell'esempio degli oggetti, se venisse aggiunta una nuova forma `Triangle` non devo fare alcuna modifica alle funzioni esistenti, ma se venisse aggiunta una nuova funzione `perimeter()` dovrei andare a modificare tutte le forme! Possiamo quindi dedurre che oggetti e strutture sono l'una l'opposto dell'altra. Le **strutture** facilitano l'aggiunta di nuove funzioni senza modificare l'assetto esistente, ma qualora venisse aggiunta una nuova struttura, dovrò modificare tutte le funzioni esistenti. Gli **oggetti**, al contrario, facilitano l'aggiunta di nuove classi senza modificare le funzioni esistenti, ma complicano l'aggiunta di nuove funzioni, perchè tutte le classi devono cambiare.

## La legge di Demetra

La *legge di Demetra* dice che un modulo non dovrebbe conoscere i dettagli degli oggetti che manipola. Significa che un oggetto non dovrebbe mostrare la propria struttura interna tramite i metodi di accesso, perché ciò vorrebbe dire esporre, e non nascondere, la propria struttura interna. Nello specifico la legge di Demetra dice che un metodo *f* di una classe *C* dovrebbe richiamare solo i metodi di:

* C
* un oggetto creato da f
* un oggetto passato come argomento a f
* un oggetto contenuto in una variabile di istanza di C

Un esempio di violazione di questa legge è dato dal seguente codice:

```
$outputDir = $ctxt->getOptions()->getScratchDir()->getAbsolutePath();
```

## Relitti ferroviari

Questo genere di codice viene chiamato "relitto ferroviario" perché ha l'aspetto di un ammasso di coppie di vagoni e generalmente va evitato. Ritornando a noi, il codice sopra riportato, viola la legge di Demetra? Ciò dipende dal fatto che *ctxt*, *options*, e *scratchDir* siano oggetti o strutture. Se sono oggetti, allora la loro struttura interna dovrebbe essere nascosta, pertanto viola la legge di Demetra. Se sono strutture, e quindi non hanno funzioni che fanno qualcosa di significativo, è normale che espongono i propri dati interni, pertanto **non** viola la legge di Demetra. L'utilizzo dei metodi di accesso confonde la situazione.

## Ibridi

Questo talvolta porta ad avere degli ibridi: per metà oggetti e per metà strutture. Hanno funzioni che fanno qualcosa di significativo, ma hanno anche *getter* e *setter* che espongono le variabili private.

## Nascondere la struttura

E se *ctxt*, *options* e *scratchDir* fossero oggetti? Come faccio a ricavarmi il percorso assoluto di scratch? Se *ctxt* fosse un oggetto, dovremmo chiedergli di **fare qualcosa** e non chiedergli i suoi dettagli interni. Continuando con il codice vediamo a cosa serve *outputDir*:

```
$outFilename = $outputDir . '/' . str_replace('.', '/', $className) . '.class';
$file = fopen($outFilename, 'w');
```

Vediamo quindi come *outputDir* serve per creare un file, ma allora perché non farlo creare direttamente a *ctxt*?

```
$file = $ctxt->createScratchFile($classFilename);
```

Ciò consente a *ctxt* di nascondere la propria struttura interna ed evita la violazione della legge di Demetra.

## Data Transfer Object (DTO)

Una struttura è una classe con variabili pubbliche (o private, ma manipolate tramite *getter* e *setter*) e senza funzioni, un cosiddetto **Data Transfer Object** o **DTO**. I DTO sono utili soprattutto per comunicare con i database. Servono per trasformare il dato "grezzo" di una tabella in oggetti dell'applicazione.

```
class Address {
    private $state;
    private $province;
    private $city;
    private $address;
    private $zip;

    public function __construct(
        string $state,
        string $province,
        string $city,
        string $address,
        string $zip
    ) {
        $this->state = $state;
        $this->province = $province;
        $this->city = $city;
        $this->address = $address;
        $this->zip = $zip;
    }

    public function getState(): string {
        return $this->state;
    }

    public function getProvince(): string {
        return $this->province;
    }

    public function getCity(): string {
        return $this->city;
    }

    public function getAddress(): string {
        return $this->address;
    }

    public function getZip(): string {
        return $this->zip;
    }
}
```

## Active Record

Gli **Active Record** sono delle forme particolari di DTO. Sono simili ai DTO, ma sono dotati di metodi di **navigazione** come *save* e *find*. Sfortunatamente spesso si tende a trattare queste strutture come se fossero oggetti, inserendovi anche metodi di manipolazione. Evitatelo! Piuttosto create degli oggetti appositi che contengono le regole operative e che nascondono i propri dati interni.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mirkorap16.gitbook.io/clean-code/oggetti-e-strutture.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
