青雲的博客

Article

单一职责原则:独孤九剑的每一式只破一种兵器

· 6 分钟阅读

单一职责就像令狐冲所学的独孤九剑。独孤九剑讲究一招一式皆有其特定的目标和用途,或破剑、或破刀、或破枪等,每一式都专注于应对一种兵器的攻击。单一职责原则也是如此,一个类只负责一项职责,如同独孤九剑的每一式都专注于破解一类兵器。 影视剧照:一名古装男子手持长剑侧身而立的特写

一个类只该有一个变更理由

单一职责原则强调:一个类应该只有一个引起它变化的原因。即,一个类只负责一个职责。

示例:员工管理与报酬管理分离

拆开之后

class Employee {
  private name: string;

  constructor(name: string) {
    this.name = name;
  }

  getName(): string {
    return this.name;
  }
}

// 职责1:员工管理
class EmployeeManager {
  private employees: Employee[] = [];

  addEmployee(employee: Employee): void {
    this.employees.push(employee);
  }

  getEmployees(): Employee[] {
    return this.employees;
  }
}

// 职责2:员工报酬管理
class EmployeePayroll {
  calculatePay(employee: Employee): number {
    // 计算员工报酬逻辑
    return 1000; // 示例
  }
}

// 使用示例
const emp1 = new Employee("Alice");
const empManager = new EmployeeManager();
empManager.addEmployee(emp1);
const payroll = new EmployeePayroll();
console.log(`Pay for ${emp1.getName()}: ${payroll.calculatePay(emp1)}`); // Pay for Alice: 1000

类图

单一职责原则结构图:Employee、EmployeeManager、EmployeePayroll 3 个角色,以及它们之间的聚合关系

  1. Employee 类负责处理员工的基本信息。
  2. EmployeeManager 类负责管理员工,如添加员工、获取员工信息等。
  3. EmployeePayroll 类负责计算员工的报酬。

体现单一职责原则的设计模式

  1. 策略模式(Strategy Pattern):通过将算法封装到具体的策略类中,使每个策略类只负责一种特定的算法逻辑,遵循单一职责原则。
  2. 装饰器模式(Decorator Pattern):通过将额外的职责封装到装饰器类中,使得每个装饰器类只负责一种特定的职责,符合单一职责原则。
  3. 观察者模式(Observer Pattern):通过将通知逻辑封装到观察者类中,使得每个观察者类只负责处理特定的通知事件,体现了单一职责原则。
  4. 命令模式(Command Pattern):通过将请求封装到具体的命令类中,使得每个命令类只负责一个特定的请求,符合单一职责原则。

前端里的四个高发场景

表单验证

在前端开发中,表单验证是一个常见的需求。可以将不同的验证逻辑封装到不同的类中,使得每个类只负责一种验证方式,如邮箱验证、手机号验证、密码强度验证等。 示例

class EmailValidator {
  validate(email: string): boolean {
    const regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/
    return regex.test(email)
  }
}

class PhoneValidator {
  validate(phone: string): boolean {
    const regex = /^\d{10}$/
    return regex.test(phone)
  }
}

class PasswordValidator {
  validate(password: string): boolean {
    return password.length >= 8
  }
}

// 使用示例
const emailValidator = new EmailValidator()
console.log(emailValidator.validate('[email protected]')) // true

const phoneValidator = new PhoneValidator()
console.log(phoneValidator.validate('1234567890')) // true

const passwordValidator = new PasswordValidator()
console.log(passwordValidator.validate('strongpass')) // true

动画处理

动画处理在前端开发中非常常见,可以将不同的动画效果封装到不同的类中,使得每个类只负责一种动画效果,如淡入淡出动画、滑动动画等。 示例

class FadeInAnimation {
  animate(element: HTMLElement): void {
    element.style.transition = 'opacity 1s'
    element.style.opacity = '1'
  }
}

class SlideInAnimation {
  animate(element: HTMLElement): void {
    element.style.transition = 'transform 1s'
    element.style.transform = 'translateX(0)'
  }
}

// 使用示例
const element = document.getElementById('myElement')
const fadeInAnimation = new FadeInAnimation()
fadeInAnimation.animate(element) // 应用淡入动画

const slideInAnimation = new SlideInAnimation()
slideInAnimation.animate(element) // 应用滑动动画

数据请求处理

在前端开发中,数据请求处理也是一个常见的应用场景。可以将不同的请求逻辑封装到不同的类中,使得每个类只负责一种请求方式,如 GET 请求、POST 请求等。 示例

class GetRequest {
  send(url: string): Promise<Response> {
    return fetch(url)
  }
}

class PostRequest {
  send(url: string, data: any): Promise<Response> {
    return fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data),
    })
  }
}

// 使用示例
const getRequest = new GetRequest()
getRequest
  .send('https://api.example.com/data')
  .then((response) => response.json())
  .then((data) => console.log(data))

const postRequest = new PostRequest()
postRequest
  .send('https://api.example.com/data', { key: 'value' })
  .then((response) => response.json())
  .then((data) => console.log(data))

数据格式化

在前端开发中,数据格式化也是经常需要处理的,可以将不同的格式化逻辑封装到不同的类中,使得每个类只负责一种格式化方式,如日期格式化、货币格式化等。 示例

class DateFormatter {
  format(date: Date): string {
    return date.toLocaleDateString()
  }
}

class CurrencyFormatter {
  format(amount: number): string {
    return `$${amount.toFixed(2)}`
  }
}

// 使用示例
const dateFormatter = new DateFormatter()
console.log(dateFormatter.format(new Date())) // 输出: 例如 12/31/2022

const currencyFormatter = new CurrencyFormatter()
console.log(currencyFormatter.format(123.456)) // 输出: $123.46

六大原则总览与其余各篇:总览开闭里氏替换依赖倒置接口隔离迪米特法则

Keep Reading

相关文章

评论