Ci sono comunque 3 cose che posso subito farti notare:

1) Taxi ha il main() quindi è il punto di ingresso per una applicazione "standalone". Se non ha interfaccia grafica e fa solo quello che vedo nel codice, allora non c'è bisogno di creare un thread. La gestione del Socket e la comunicazione potrebbe essere benissimo fatta nel "main" thread (quello appunto che esegue il main() ).

2) Gestore idem come sopra, ha il main() quindi lo usi come applicazione standalone. Idem non servirebbe strettamente creare un thread per il loop di accept, che invece potrebbe andare tranquillamente nel main thread.

3) Taxi però fa sia da entry point della applicazione, sia "modella" le informazioni di un taxi. E tu al server invii appunto una istanza di Taxi. Il fatto che rappresenti 2 cose distinte (applicazione e taxi) non va bene. Fai una classe Taxi che modella solo un taxi e un'altra classe es. ClienteTaxi (con main, Socket, ecc...).