SOLID: Liskov’s Substitution Principle — With Real Life Example

export default interface ICacheService {
setCache<T>(key: string, value: T): Promise<boolean>;
getCache<T>(key: string): Promise<T>;
checkCacheExists(key: string): Promise<boolean>;
setCacheWithTimeout<T>(
key: string,
value: T,
timeout: number
): Promise<boolean>;
}
import ICacheService from "../ICacheService";
import fs from "fs";

export default class FileStreamCacheService implements ICacheService {
private cacheDir: string = "./cacheFiles/";
private cacheExtension: string = ".txt";
constructor() {}

private calculateCachePath = (key: string): string => {
return this.cacheDir + key + this.cacheExtension;
};

checkCacheExists = async (key: string): Promise<boolean> => {
return fs.existsSync(this.calculateCachePath(key));
};

getCache = async <T>(key: string): Promise<T> => {
return new Promise<T>((resolve, reject) => {
fs.readFile(this.calculateCachePath(key), (err, result) => {
if (err) return reject(err);
resolve(JSON.parse(result.toString()));
});
});
};

setCache = async <T>(key: string, value: T): Promise<boolean> => {
return new Promise<boolean>((resolve, reject) => {
fs.writeFile(
this.calculateCachePath(key),
JSON.stringify(value),
(err: any) => {
if (err) return reject(false);
resolve(true);
}
);
});
};

setCacheWithTimeout = <T>(
key: string,
value: T,
timeout: number
): Promise<boolean> => {
return Promise.resolve(false);
};
}
import ICacheService from "../ICacheService";
import redis from "redis";

export default class RedisCacheService implements ICacheService {
private redisClient: redis.RedisClientType;

constructor(redisClient: redis.RedisClientType) {
this.redisClient = redisClient;
}

checkCacheExists = async (key: string): Promise<boolean> => {
return (await this.redisClient.exists(key)) === 1;
};

getCache = async <T>(key: string): Promise<T> => {
const result = await this.redisClient.get(key);
if (!result) throw new Error(`Not found: ${key}`);
return JSON.parse(result);
};

setCache = async <T>(key: string, value: T): Promise<boolean> => {
const result = await this.redisClient.set(key, JSON.stringify(value));
return result === "OK";
};

setCacheWithTimeout = async <T>(
key: string,
value: T,
timeout: number
): Promise<boolean> => {
const result = await this.redisClient.setEx(
key,
timeout,
JSON.stringify(value)
);
return result === "OK";
};
}
import redis, { createClient } from "redis";
import ICacheService from "./cache/ICacheService";
import RedisCacheService from "./cache/redis/RedisCacheService";

const createRedis = async (): Promise<redis.RedisClientType> => {
const client: redis.RedisClientType = createClient();
await client.connect();
return client;
};

class Product {
name: string;
id: number;
price: number;

constructor(name: string, id: number, price: number) {
this.name = name;
this.id = id;
this.price = price;
}
}

(async () => {
const redisClient = await createRedis();

const cacheService: ICacheService = new RedisCacheService(redisClient);

const supra = new Product("Toyota Supra", 22, 10000);

const setExpireResult = await cacheService.setCacheWithTimeout<Product>(
"product_22",
supra,
3
);

console.log("is it set Supra ? ", setExpireResult);

const supraIsThereOne = await cacheService.checkCacheExists("product_22");
console.log("is there Supra ? ", supraIsThereOne);

setTimeout(async () => {
const supraIsThereTwo = await cacheService.checkCacheExists("product_22");
console.log("is there still Supra ? ", supraIsThereTwo);
}, 3100);
})();
export default interface ICacheService {
setCache<T>(key: string, value: T): Promise<boolean>;
getCache<T>(key: string): Promise<T>;
checkCacheExists(key: string): Promise<boolean>;
}

export interface ITimeoutCacheService extends ICacheService {
setCacheWithTimeout<T>(
key: string,
value: T,
timeout: number
): Promise<boolean>;
}

--

--

--

Hello, I am Sami Salih İbrahimbaş. I am a 20 year old Full Stack Developer living and working in Turkey.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Launching A Free Newsletter for Developers

3 Steps to deploy ReactJS to AppEngine Standard

Developing a performant custom cursor

TypeScript Spymasters

JavaScript Object Methods & Looping

Web Chat Application

Why your Polymer app is slow in Non-Chromium Browsers and how to make it fast

Testing strategies for modern web applications

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sami Salih İbrahimbaş

Sami Salih İbrahimbaş

Hello, I am Sami Salih İbrahimbaş. I am a 20 year old Full Stack Developer living and working in Turkey.

More from Medium

SOLID: What is? Why this? How use?

Clean Code Development | Integration Operation Separation Principle

Reuse RabbitMQ connection

An Overview of Cache & its Types