The singleton pattern ensures that a class has only one instance and provides a global point of access to it.
✅ Single Responsibility Principle (SRP)
✅ Open/Closed Principle (OCP): The Abstract Product is open to extend.
✅ Liskov Substitution Principle (LSP) / Interface Segregation Principle (ISP): ⚠️ If Concrete Objects implement Abstract Object correctly.
✅ Dependency Inversion Principle (DIP): The object doesn’t rely on another concrete objects.
abstract class Logger {
abstract log(message: string): void;
// Reusable Shared Logic
protected formatMessage(message: string): string {
const timestamp = new Date().toISOString();
return `[${timestamp}] ${message}`;
}
}
class ConsoleLogger extends Logger {
private static instance: ConsoleLogger;
private constructor() {
super();
}
static getInstance(): ConsoleLogger {
if (!ConsoleLogger.instance) {
ConsoleLogger.instance = new ConsoleLogger();
}
return ConsoleLogger.instance;
}
public log(message: string): void {
const formatted = this.formatMessage(message);
console.log(formatted);
}
}
// Client
const logger = ConsoleLogger.getInstance();
logger.log("Shared logic works!");
interface Logger {
log(message: string): void;
// Reusable Shared Logic
formatMessage(message: string): string
}
class ConsoleLogger implements Logger {
private static instance: ConsoleLogger;
private constructor() {}
static getInstance(): ConsoleLogger {
if (!ConsoleLogger.instance) {
ConsoleLogger.instance = new ConsoleLogger();
}
return ConsoleLogger.instance;
}
public log(message: string): void {
const formatted = this.formatMessage(message);
console.log(formatted);
}
private formatMessage(message: string): string {
const timestamp = new Date().toISOString();
return `[${timestamp}] ${message}`;
}
}
// Client
const logger = ConsoleLogger.getInstance();
logger.log("Shared logic works!");
Go lacks encapsulation mechanisms (private, protected, public).
type Logger interface {
Log(message string)
// Reusable Shared Logic
formatMessage(message string) string
}
type ConsoleLogger struct {}
func (c *ConsoleLogger) Log(message string) {
formatted := c.formatMessage(message)
fmt.Println(formatted)
}
func (c *ConsoleLogger) formatMessage(message string) string {
timestamp := time.Now().Format(time.RFC3339)
return fmt.Sprintf("[%s] %s", timestamp, message)
}
var (
consoleLoggerInstance *ConsoleLogger
once sync.Once
)
func GetConsoleLogger() *ConsoleLogger {
once.Do(func() {
consoleLoggerInstance = &ConsoleLogger{}
})
return consoleLoggerInstance
}
// Client
func main() {
logger := GetConsoleLogger()
logger.Log("Shared logic works!")
}
type Logger interface {
Log(message string)
}
type LoggerBase struct{}
// Reusable Shared Logic
func (l LoggerBase) formatMessage(message string) string {
timestamp := time.Now().Format(time.RFC3339)
return fmt.Sprintf("[%s] %s", timestamp, message)
}
type ConsoleLogger struct {
LoggerBase
}
func (c ConsoleLogger) Log(message string) {
formatted := c.formatMessage(message)
fmt.Println(formatted)
}
// ... same code