Qual è la motivazione o l'utilizzo per creare un'interfaccia, usata una volta solo per rompere la dipendenza circolare?

3

Capisco se 2 classi hanno una dipendenza circolare, ad esempio:

public class MyWindow{
    public MyWindow(){
        new MyDialog(this);
    }

    public onDialogResponse(int option){
    }
}

public class MyDialog{
    MyWindow myWindow;
    public MyDialog(MyWindow myWindow){
        this.myWindow=myWindow;
    }

    public void onClicked(int option){
        this.myWindow.onDialogResponse(option);
    }
}

possiamo interrompere la dipendenza circolare creando un'interfaccia, ad esempio:

public interface IWindow{
    void onDialogResponse(int option);
}

public class MyWindow implements IWindow{
    public MyWindow(){
        new MyDialog(this);
    }

    public onDialogResponse(int option){
    }
}

public class MyDialog{
    IWindow myWindow;
    public MyDialog(IWindow myWindow){
        this.myWindow=myWindow;
    }

    public void onClicked(int option){
        this.myWindow.onDialogResponse(option);
    }
}

ma la mia domanda è, se IWindow è usato una volta solo per rompere la dipendenza circolare, vale la pena farlo? perché penso che anche se la dipendenza circolare sembra scadente, l'interruzione della dipendenza circolare in questo caso genera un codice più complesso quando viene creata un'interfaccia aggiuntiva. C'è qualche motivazione pratica o utilizzo per creare un'interfaccia solo per rompere la dipendenza circolare come in questo caso?

    
posta ggrr 16.06.2017 - 04:37
fonte

3 risposte

4

Is there any practical motivation or usage to create a interface just for breaking circular dependency like this case?

Sì, c'è. L'introduzione di un'interfaccia disaccoppia MyDialog da una dipendenza su MyWindow . Questo è utile per diversi motivi:

  • Come hai osservato, impedisce una dipendenza circolare
  • Ti permette di testare l'unità MyDialog in isolamento prendendo in giro IWindow
  • Utilizza un modello di "listener" comune utilizzato nella maggior parte delle UI per i componenti per notificare i client quando si verificano eventi. (questa giustificazione sarebbe più valida se IWindow fosse chiamato qualcosa di più significativo come IDialogListener ). In questo caso non deve essere usato una sola volta. Puoi continuare a utilizzare questo modello di listener per tutte le tue finestre di dialogo.
  • Non limita l'uso di MyDialog a MyWindow . MyDialog ora può essere riutilizzato da qualsiasi componente che implementa IWindow .
  • MyDialog può essere fornita implementazione anonima di IWindow invece di dover implementare onDialogResponse() in MyWindow . Ciò consente a MyWindow o a qualsiasi altro componente di creare più istanze di MyDialog e gestirne i risultati in modo indipendente. Ad esempio:
public MyWindow() {
    MyDialog dlg1 = new MyDialog(new IWindow() {...});
    MyDialog dlg2 = new MyDialog(new IWindow() {...});
}
    
risposta data 16.06.2017 - 04:53
fonte
4

Sono d'accordo che l'introduzione di un'interfaccia qui non sia troppo utile. Samuel offre alcuni benefici legittimi, ma nella mia mente l'interfaccia sta spazzando via il problema del design sotto il tappeto. Il vero problema è che Window e Dialog sono stati strettamente accoppiati. Questo accoppiamento è fatto in due modi

  1. La finestra crea istantaneamente un dialogo.
  2. Il dialogo richiama in un metodo di finestra esplicitamente progettato per essere chiamato dal dialogo.

Sono entrambi i collegamenti che portano alla circolarità, ma penso che entrambi i link valgano individualmente. Potremmo interrompere il primo collegamento usando l'iniezione di dipendenza, anche se senza conoscere più contesto non è chiaro quale sia la relazione tra la finestra di dialogo e la finestra (la finestra deve avere una finestra di dialogo, ha bisogno della possibilità di produrre una finestra di dialogo a comando, possono invece essere liberi, ecc.) quindi non si può essere troppo concreti. Nell'altra direzione, un'opzione basata su eventi è una scelta naturale e popolare per separare i componenti dell'interfaccia utente. In questo caso la finestra di dialogo appena annuncia (ad esempio, pubblica su una coda di messaggi) "I, la finestra di dialogo, è stata selezionata con questa opzione" e la finestra o qualche altro utente può decidere cosa fare con tali informazioni.

Quanto elaborato e strutturato vuoi andare con questo dipende dalla complessità della tua applicazione. Se tutto quello che prevedi di avere una finestra e una finestra di dialogo che si adattano a un paio di schermate, allora onestamente puoi mantenere il design attuale. In generale, tuttavia, penso che non si debbano aggiungere interfacce alla carta per un cattivo design, ma per aggiungere flessibilità a un design strong.

    
risposta data 16.06.2017 - 06:22
fonte
2

Sebbene ci siano molti buoni motivi per usare un'interfaccia, il tuo esempio non è uno di questi.

Le dipendenze circolari spesso evidenziano l'accoppiamento nel nostro progetto.

Nel tuo caso Dialogue dovrebbe esporre un evento hander Clicca su quale Finestra poi assegna piuttosto che conoscere il suo genitore.

Questo consente di utilizzarlo in più posti oltre a una finestra.

Se ritieni che il Dialogo debba controllare cosa succede quando i suoi eventi si attivano, l'interfaccia che inietterai dovrebbe essere adattata a tale compito. ICanHandleClick o qualcosa del genere, che implica quindi che può essere utilizzato in generale. Non solo Window: IWindow

    
risposta data 16.06.2017 - 11:29
fonte