Io preferisco la seconda soluzione, + adatta soprattutto nel caso in cui puoi raccogliere le varie funzionalità del programma in delle classi completamente svincolate dall'interfaccia (diciamo "classi funzionali"), e che offrono dei metodi per eseguire determinate azioni; queste classi non dovrebbero neanche implementare ActionListener. Le classi che realizzano l'interfaccia dovrebbero implementare ActionListener e invocare gli opportuni metodi delle classi funzionali quando ricevono un evento dell'utente. Una stessa funzionalità potrebbe ad esempio essere richiesta dall'utente per mezzo di un altro componente grafico che non genera ActionEvent, ma un altro tipo di evento; in questo modo le classi funzionali non devono preoccuparsi di come avviene l'interazione con l'utente, ma si limitano ad offrire dei metodi che possono essere invocati all'occorrenza. Ovviamente non c'è una regola migliore di un'altra, da preferire in assoluto; questa linea di progettazione aumenta la flessibilità dell'applicazione e nel caso di grosse applicazioni ne aumenta la leggibilità ancorchè diminuirla, ed è da preferire se l'spetto della progettazione è fondamentale nello sviluppo dell'applicazione. Viceversa nel caso di piccole applicazioni in cui non ci siano delle classi che offrono le funzionalità richieste dall'interfaccaia, e non sia necessario separarle dalla grafica, può essere convenitente la seconda soluzione.
Ciao.