Cuando un equipo / empresa envía un marco / compilador / conjunto de herramientas, ya tiene algo de experiencia, un conjunto de mejores prácticas. Lo comparten como pautas. Las pautas son recomendaciones . Si no le gusta ninguno, puede ignorarlo. El compilador aún compilará su código. Aunque cuando en Roma ...
Esta es mi visión por la que el equipo de TypeScript recomienda no I
prefijar interfaces.
Razón # 1 Los tiempos de la notación húngara han pasado
El argumento principal de los I
partidarios de -prefix-for-interface es que el prefijo es útil para asimilar (mirar) inmediatamente si el tipo es una interfaz. La declaración de que el prefijo es útil para asimilar inmediatamente (mirar a escondidas) es una apelación a la notación húngara . I
prefijo para el nombre de la interfaz, C
para la clase, A
para la clase abstracta, s
para la variable de cadena, c
para la variable constante, i
para la variable entera. Estoy de acuerdo en que dicha decoración de nombre puede proporcionarle información de tipo sin pasar el mouse sobre el identificador o navegar hasta la definición de tipo a través de una tecla de acceso rápido. Este pequeño beneficio se ve compensado por las desventajas de la notación húngara y otras razones que se mencionan a continuación. La notación húngara no se utiliza en marcos contemporáneos. C # tieneI
prefijo (y este es el único prefijo en C #) para interfaces debido a razones históricas (COM). En retrospectiva, uno de los arquitectos de .NET (Brad Abrams) piensa que hubiera sido mejor no usar el I
prefijo . TypeScript es COM-legacy-free, por lo que no tiene la I
regla -prefix-for-interface.
Razón # 2: el I
prefijo viola el principio de encapsulación
Supongamos que obtiene una caja negra. Obtienes algún tipo de referencia que te permite interactuar con ese cuadro. No debería importarle si es una interfaz o una clase. Solo usa su parte de interfaz. Exigir saber qué es (interfaz, implementación específica o clase abstracta) es una violación de la encapsulación.
Ejemplo: supongamos que necesita arreglar API Design Myth: Interface as Contract en su código, por ejemplo, elimine la ICar
interfaz y use Car
la clase base en su lugar. Entonces debe realizar dicho reemplazo en todos los consumidores. I
-prefix conduce a una dependencia implícita de los consumidores en los detalles de implementación de la caja negra.
Razón # 3 Protección de nombres incorrectos
Los desarrolladores son perezosos para pensar correctamente en los nombres. Nombrar es una de las dos cosas difíciles de la informática . Cuando un desarrollador necesita extraer una interfaz, es fácil agregar la letra I
al nombre de la clase y obtendrá un nombre de interfaz. No permitir el I
prefijo para las interfaces obliga a los desarrolladores a esforzarse en elegir los nombres adecuados para las interfaces. Los nombres elegidos deben ser diferentes no solo en el prefijo, sino también enfatizar la diferencia de intención.
Abstracción caso: usted debe no no definir una ICar
interfaz y un asociado Car
de clase. Car
es una abstracción y debe ser la utilizada para el contrato. Las implementaciones deben tener nombres descriptivos y distintivos, por ejemplo SportsCar, SuvCar, HollowCar
.
Buen ejemplo: WpfeServerAutosuggestManager implements AutosuggestManager
, FileBasedAutosuggestManager implements AutosuggestManager
.
Mal ejemplo: AutosuggestManager implements IAutosuggestManager
.
En mi práctica, conocí a mucha gente que sin pensarlo duplicaba parte de la interfaz de una clase en una interfaz separada que tenía un Car implements ICar
esquema de nombres. Duplicar parte de la interfaz de una clase en un tipo de interfaz separada no la convierte mágicamente en abstracción. Aún obtendrá una implementación concreta pero con una parte de interfaz duplicada. Si su abstracción no es tan buena, duplicar la parte de la interfaz no la mejorará de todos modos. Extraer abstracción es un trabajo duro.
NOTA: En TS no necesita una interfaz separada para burlarse de las clases o sobrecargar la funcionalidad. En lugar de crear una interfaz separada que describa a los miembros públicos de una clase, puede usar tipos de utilidad de TypeScript . Por ejemplo, Required<T>
construye un tipo que consta de todos los miembros públicos del tipo T
.
export class SecurityPrincipalStub implements Required<SecurityPrincipal> {
public isFeatureEnabled(entitlement: Entitlement): boolean {
return true;
}
public isWidgetEnabled(kind: string): boolean {
return true;
}
public areAdminToolsEnabled(): boolean {
return true;
}
}
Si desea construir un tipo que excluya a algunos miembros públicos, puede usar la combinación de Omitir y Excluir .
I
prefijo tiene sentido para usted y su equipo, ÚSELO. Si no, tal vez el estilo Java deSomeThing
(interfaz) conSomeThingImpl
(implementación) entonces por todos los medios úselo.