Se il frame B deve poter fare qualcosa in modo "attivo" per cambiare la lista che ha il frame A, allora ci sono almeno 2 opzioni:
a) Al frame B passi il model (attenzione, non il componente JList, non sarebbe buona cosa). Chiaramente il frame B può fare sul model tutto ciò che la classe del model offre di pubblico. Se frame B sa di ricevere un DefaultListModel, può fare tutto quello che DefaultListModel permette.
b) Al frame B passi un oggetto di una tua interfaccia Xyz che ha i soli metodi che vuoi permettere per aggiornare la lista. La interfaccia può essere implementata nel model (se è uno tuo specifico, sotto il tuo controllo) oppure in una classe anche nascosta che accede al model. Il punto è che frame B "vede" solo la interfaccia. Se avesse solo un metodo es. aggiungiFile(String), solo questo può fare.
Se frame B invece non compie nulla di attivo per cambiare la lista, allora si può:
c) in frame B metti un metodo es. getFileAggiunti() e il frame A lo usa appena riceve notifica che frame B si è chiuso.
d) definisci un nuovo vero e proprio listener (nello stile degli altri di AWT/Swing) es. FileCreationListener con un es. fileCreated(FileCreationEvent).
Il frame A implementa in qualche modo il listener e poi lo "registra" sul frame B. Frame B notifica solo la creazione, poi frame A fa quello che vuole.
Ci potrebbero essere altri scenari possibili. Questi sono solo alcuni che mi vengono in mente. Come vedi è sempre tutto relativo ad un metodo X che viene invocato su un oggetto Y. Quello che varia e che dà origine ad un design differente è il chi invoca cosa su quale oggetto e con quale livello di astrazione riguardo il tipo.![]()