Inyección de dependencias
Inyectar o añadir una dependencia a otra clase para evitar que toda la lógica o uso de otros paquetes esté dentro de la clase principal.
La inyección de dependencias crea otra propiedad en la clase.
Ej. Si se está utilizando Axios en una petición HTTP dentro de la clase, entonces se extrae y así, si es necesario cambiar a otro método como Fetch, no se debe cambiar la lógica dentro de la clase principal, solo la procedencia de la fuente de los datos.
1. Definir adapter
.adapter. es una clase que adapta la funcionalidad de un paquete de terceros
src\api\pokeApi.adapter.ts
import axios from "axios";
export class PokeApiAdapter {
private readonly axios = axios;
// peticion get
// tipar response con <T>, que es un generico
// se recibe al usar el metodo
async get<T>(url: string): Promise<T> {
const { data } = await axios.get<T>(url);
return data;
}
async post(url: string, data: any) {}
async path(url: string, data: any) {}
async delete(url: string) {}
}
2. Implementar dependencias
import { PokeApiAdapter, PokeApiFetchAdapter } from "../api/pokeApi.adapter";
import { Move, PokeapiResponse } from "./interfaces/pokeapi-response.interface";
export class Pokemon {
constructor(
public readonly id: number,
public name: string,
// 1. inyectar dependencias en el contrsuctor
private readonly http: PokeApiAdapter
) {}
speak() {
console.log(`${this.name}, ${this.name}`);
}
// 2. Usar el adatper o la inyeccion de dependencias
async getMoves(): Promise<Move[]> {
// http.get lo definimos en nuestro adapter
// recibe un generico tipo de dato
const data = await this.http.get<PokeapiResponse>(
"https://pokeapi.co/api/v2/pokemon/4"
);
console.log(data.moves[0].move.name);
return data.moves;
}
}
// USO -------------------------------------------------------------------------------
// 3. Crear una instancia del adapter
const pokeApi = new PokeApiAdapter();
const pokeApiFetch = new PokeApiFetchAdapter();
// 4. Inyectar la dependencia en la instancia de la clase
export const charmander = new Pokemon(4, "Charmander", pokeApi);
// Otros objectos o instancias pueden usar la misma instancia del adapter
export const otro = new Pokemon(5, "Otro", pokeApi);
charmander.getMoves();
Sustitución de Liskov
1. Interface y dependencia
import axios from "axios";
// 1. interface para usar en el adapter y constructor de una clase
// tambien se podria usar una clase abstracta
export interface HttpAdapter {
get<T>(url: string): Promise<T>;
}
// 2. adapter e implementar la interface
export class PokeApiFetchAdapter implements HttpAdapter {
// 3. implementar el metodo de la interface
async get<T>(url: string): Promise<T> {
const resp = await fetch(url);
const data: T = await resp.json();
console.log("Con Fetch");
return data;
}
}
// 2. otro adapter que tambien implementa la interface
export class PokeApiAdapter implements HttpAdapter {
private readonly axios = axios;
// 3. implementar el metodo de la interface
async get<T>(url: string): Promise<T> {
const { data } = await axios.get<T>(url);
console.log("Con Axios");
return data;
}
}
2. Implementación
export class Pokemon {
constructor(
public readonly id: number,
public name: string,
// 1. inyectar la interface en el constructor
// Es del tipo de la interface y no del adapter
private readonly http: HttpAdapter
) {}
// 2. Usar el adatper o la inyeccion de dependencias
async getMoves(): Promise<Move[]> {
// http.get lo definimos en nuestro adapter
// tipado con <PokeapiResponse>
const data = await this.http.get<PokeapiResponse>(
"https://pokeapi.co/api/v2/pokemon/4"
);
console.log(data.moves[0].move.name);
return data.moves;
}
}
// 3. Crear instancias de los adapters
const pokeApiAxios = new PokeApiAdapter();
const pokeApiFetch = new PokeApiFetchAdapter();
// Ambas instancias implementan distintos adapters
// pero que siguen la misma interface o regla
export const charmander = new Pokemon(4, "Charmander", pokeApiAxios);
export const bulbasaur = new Pokemon(1, "Bulbasaur", pokeApiFetch);
// Otros objectos o instancias pueden usar la misma instancia del adapter
export const otro = new Pokemon(5, "Otro", pokeApiAxios);