Me hice esta pregunta en una entrevista.
Hay 3 clases A
, B extends A
y C extends B
. Tenemos que diseñar estas clases se ajusten a estas limitaciones
- El cliente puede crear una instancia de una sola instancia de
A
, una instancia deB
y un caso deC
uso de su constructor por defecto con lanew
palabra clave. - Tratando de crear otra instancia de cualquiera de estas clases resultará en una excepción.
- El diseñador de la clase tienen que cumplir lo anterior 2 reglas, por lo que el cliente va a experimentar las reglas anteriores de forma implícita (es decir, no debe ser responsabilidad del cliente para ajustarse a las reglas anteriores).
Sugerí un enfoque utilizando una static Map<Class, Object>
. Así, por ejemplo, cuando alguien llama new B()
sería comprobar si map.contains(B.class)
. Si sí, entonces lanzan una excepción y si no, entonces Guardar ejemplo, en un mapa y dejar que el objeto se creará.
Sin embargo, la siguiente pregunta era cómo iba a cumplir este enfoque en cada clase ? Según mi enfoque de cada constructor tendría que rellenar cuidadosamente el mapa de lo contrario se romperá la restricción.
¿Cómo iba a resolver este problema?
Sin embargo, la siguiente pregunta era cómo iba a cumplir este enfoque en cada clase? Según mi enfoque de cada constructor tendría que rellenar cuidadosamente el mapa de lo contrario se romperá la restricción.
Simplemente poniendo ese mapa, y el código de alrededor de ella en alguna clase de utilidad distinta. De manera que cada uno y de sus clases podría hacer algo como:
public WhateverClassConstructor() {
synchroized(someLock) {
SingeltonChecker.ensureUnique(this);
con
public static void ensureUnique(Object objectToAdd) {
Class<?> classToAdd = o.getClass();
...
Y teniendo en cuenta el hecho de que C parte B parte A, es probable que sólo necesita esa llamada en el constructor de la clase A. Por otro lado, se imagina que su primera llamada a new C()
causas una excepción con la C-constructor, pero una segunda llamada no lo haría . Por supuesto, esto es un problema en sí mismo, pero aún así, la pregunta sigue siendo: ¿cómo garantizar un objeto se completa y correctamente inicializado antes de añadir a dicho mapa ?!
Por lo tanto: hay un montón de cosas a considerar al escribir dicho código de utilidad. Por tanto, mi respuesta sería centrarse en la estúpida-dad del punto de diseño dado poco práctica, casi, y sugerir a tirar a la basura e ir a por otras soluciones, por ejemplo, algo tan simple como:
public enum SingletonObjectHolder {
private final Object hold;
A_INSTANCE(new A()), B_INSTANCE(new B())...
public Object getSingleton() { return hold; }
private SingletonObjectHolder(Object o) { hold = o };
No pierda demasiado tiempo tratando de darle a la gente una respuesta técnica, cuando el verdadero punto es no pegarse un tiro en el pie. Y no se equivoque: conseguir que el enfoque basado en el mapa "Singleton" al trabajo robusta y correcta, para todo tipo de contextos, considerar que realmente difícil .
En otras palabras: si me gustaría hacer esta pregunta en una entrevista, me gustaría escuchar una respuesta que desafía ese momento horrible diseño. Claro, pasado el 10% de su tiempo de esbozar una solución para la situación dada. Pero que pasan el 90% del tiempo a explicar por qué es tan malo, y por qué otras soluciones serían mucho mejor.