一、设计思想与原则(SOLID)
1. 单一职责原则(Single Responsibility Principle,SRP)
核心思想:一个东西只干一件事。
例子:
- 错误:一个
LoginButton
组件既处理点击事件,又发网络请求,还显示成功动画。 - 正确:拆成
LoginButton
(只管显示和点击)、AuthService
(发请求)、SuccessAnimation
(播放动画),各干各的。
前端理解:就像 CSS、HTML、JS 分开管样式、结构、逻辑一样,一个组件别啥都干。
2. 开放/封闭原则(Open/Closed Principle,OCP)
核心思想:代码欢迎新功能加入,但不爱改老代码。
例子:
- 错误:有个
ProductCard
组件,每次加新字段(价格、折扣)都改它的代码。 - 正确:设计一个
ProductCard
基组件,然后用props
或插槽(slot)扩展功能,比如<ProductCard><Price /><Discount /></ProductCard>
,新需求只加新组件。
前端理解 :就像用 React 的 props
或 Vue 的 slot
,新东西插进来,老代码不动。
3. 里氏替换原则(Liskov Substitution Principle,LSP)
核心思想:子类能无缝替换父类,不出乱子。
例子:
- 错误:
Button
是单机触发,FancyButton
改成双击触发,用它替换Button
时功能就不对了。 - 正确:
FancyButton
继承Button
,保留单机触发,只加动画效果,替换时没问题。
前端理解:就像 CSS 继承,子元素别把父元素的样式完全颠覆,保持一致性。
4. 接口隔离原则(Interface Segregation Principle,ISP)
核心思想:别强迫用东西的人接受不需要的功能。
例子:
- 错误:一个
UserAPI
接口塞了所有用户相关方法,组件用时得全接。 - 正确:拆成
AuthAPI
(login
、logout
)和ProfileAPI
(getProfile
、sendEmail
),组件按需引入。
前端理解 :就像组件的 props
,只传用得上的,别一股脑全塞进去。
5. 依赖反转原则(Dependency Inversion Principle,DIP)
核心思想:高层别直接依赖底层,大家都依赖抽象。
例子:
- 错误:
LoginForm
里写死fetchLogin()
,换成axiosLogin()
得改组件。 - 正确:定义个
loginService
接口,LoginForm
只管调用loginService.login()
,具体用fetch
还是axios
通过props
传进来。
前端理解 :就像 React 的 useContext
或 Vue 的 provide/inject
,组件不关心数据咋来的,只管用。
二、常用设计模式
1. 单例模式
-
定义: 确保一个类只有一个实例,并提供全局访问点
-
应用场景:
- 需要全局唯一对象时,如配置管理器、日志记录器、数据库连接池。
- 避免资源浪费或状态冲突
typescript
class Singleton {
private static instance: Singleton | null = null;
constructor(){}
public static getInstance(){
if(this.instance === null){
this.instance = new Singleton()
}
return this.instance
}
}
2. 工厂模式
-
定义: 通过工厂类创建对象,隐藏对象创建的细节,提供统一的创建接口。
-
应用场景:
- 对象创建复杂或需要根据条件动态选择类型时,如UI组件库、数据库驱动实例化。
- 解耦对象创建与使用。
typescript
// 1. 定义产品接口
interface WebComponent {
render(): string;
}
// 2. 具体产品类 - 按钮
class Button implements WebComponent {
private label: string;
constructor(label: string) {
this.label = label;
}
render(): string {
return `<button>${this.label}</button>`;
}
}
// 3. 具体产品类 - 输入框
class Input implements WebComponent {
private placeholder: string;
constructor(placeholder: string) {
this.placeholder = placeholder;
}
render(): string {
return `<input type="text" placeholder="${this.placeholder}" />`;
}
}
// 4. 工厂类 - 负责创建组件
class ComponentFactory {
static createComponent(type: string, props: string): WebComponent {
switch (type.toLowerCase()) {
case "button":
return new Button(props);
case "input":
return new Input(props);
default:
throw new Error(`Unknown component type: ${type}`);
}
}
}
// 5. 使用示例
function main() {
// 通过工厂创建按钮
const button = ComponentFactory.createComponent("button", "Click Me");
console.log(button.render()); // 输出: <button>Click Me</button>
// 通过工厂创建输入框
const input = ComponentFactory.createComponent("input", "Enter text here");
console.log(input.render()); // 输出: <input type="text" placeholder="Enter text here" />
}
main();
3. 发布订阅模式
-
定义: 发布者发出事件,订阅者接收事件,通过事件中心解耦两者关系
-
应用场景:
- 异步通信,如消息队列、事件总线。
- Web开发中的DOM事件监听、实时通知系统。
typescript
class EventEmitter {
private listeners: { [key: string]: { cb: Function; priority: number }[] };
constructor() {
this.listeners = {};
}
on(type, cb: Function, options) {
if (typeof type !== "string" || typeof cb !== "function") {
return false;
}
this.listeners[type] = this.listeners[type] || [];
this.listeners[type].push({
cb,
priority: options.priority,
});
return () => {
this.listeners[type] = this.listeners[type].filter(
(item) => item.cb !== cb
);
};
}
emit(type, data) {
if (typeof type !== "string") {
return false;
}
if (this.listeners[type]) {
this.listeners[type]
.sort((a, b) => a.priority - b.priority)
.forEach((item) => {
item.cb.call(null, data);
});
}
}
}
4. 观察者模式
-
定义: 对象(主题)维护一组观察者,当主题状态变化时通知所有观察者。
-
应用场景:
- 一对多依赖关系,如UI控件状态更新、数据模型变化通知视图。
- 与发布订阅类似,但更直接绑定主题与观察者。
typescript
// 1. 定义观察者接口
interface Observer {
update(news: string): void;
}
// 2. 定义主题接口
interface Subject {
attach(observer: Observer): void; // 添加观察者
detach(observer: Observer): void; // 移除观察者
notify(): void; // 通知所有观察者
}
// 3. 具体主题类 - 新闻发布者
class NewsAgency implements Subject {
private observers: Observer[] = [];
private latestNews: string = "";
// 添加观察者
attach(observer: Observer): void {
if (!this.observers.includes(observer)) {
this.observers.push(observer);
}
}
// 移除观察者
detach(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}
// 通知所有观察者
notify(): void {
for (const observer of this.observers) {
observer.update(this.latestNews);
}
}
// 发布新新闻并触发通知
publishNews(news: string): void {
this.latestNews = news;
this.notify();
}
}
// 4. 具体观察者类 - 订阅者
class Subscriber implements Observer {
private name: string;
constructor(name: string) {
this.name = name;
}
update(news: string): void {
console.log(`${this.name} 收到新闻: ${news}`);
}
}
// 5. 使用示例
function main() {
// 创建新闻发布者
const newsAgency = new NewsAgency();
// 创建订阅者
const sub1 = new Subscriber("张三");
const sub2 = new Subscriber("李四");
const sub3 = new Subscriber("王五");
// 订阅者订阅新闻
newsAgency.attach(sub1);
newsAgency.attach(sub2);
newsAgency.attach(sub3);
// 发布新闻
newsAgency.publishNews("明天放假啦!");
// 输出:
// 张三 收到新闻: 明天放假啦!
// 李四 收到新闻: 明天放假啦!
// 王五 收到新闻: 明天放假啦!
// 移除一个订阅者
newsAgency.detach(sub2);
// 再次发布新闻
newsAgency.publishNews("后天加班哦!");
// 输出:
// 张三 收到新闻: 后天加班哦!
// 王五 收到新闻: 后天加班哦!
}
main();
5. 代理模式
-
定义: 为目标对象提供一个代理,控制对目标的访问。
-
应用场景:
- 延迟加载(如图片懒加载)、权限控制、缓存代理。
- Web开发中常见的API请求拦截。
csharp
interface IUserDao {
save(): void;
}
/**
* 接口实现
* 目标对象
*/
class UserDao implements IUserDao {
public save(): void {
console.log("----已经保存数据!----");
}
}
/**
* 代理对象,静态代理
*/
class UserDaoProxy implements IUserDao {
//接收保存目标对象
private target: IUserDao;
constructor(target: IUserDao) {
this.target = target;
}
public save(): void {
this.target.save(); //执行目标对象的方法
}
}
6. 策略模式
-
定义: 定义一系列算法,封装并使它们可互换,客户端动态选择策略。
-
应用场景:
- 动态切换行为,如排序算法选择、支付方式切换。
- 避免大量条件语句。
typescript
// 1. 定义策略接口
interface PaymentStrategy {
pay(amount: number): string;
}
// 2. 具体策略类 - 支付宝支付
class AlipayStrategy implements PaymentStrategy {
pay(amount: number): string {
return `使用支付宝支付 ${amount} 元`;
}
}
// 3. 具体策略类 - 微信支付
class WechatStrategy implements PaymentStrategy {
pay(amount: number): string {
return `使用微信支付 ${amount} 元`;
}
}
// 4. 具体策略类 - 信用卡支付
class CreditCardStrategy implements PaymentStrategy {
pay(amount: number): string {
return `使用信用卡支付 ${amount} 元`;
}
}
// 5. 上下文类 - 支付处理器
class PaymentProcessor {
private strategy: PaymentStrategy;
constructor(strategy: PaymentStrategy) {
this.strategy = strategy;
}
// 设置策略
setStrategy(strategy: PaymentStrategy): void {
this.strategy = strategy;
}
// 执行支付
processPayment(amount: number): string {
return this.strategy.pay(amount);
}
}
// 6. 使用示例
function main() {
// 创建支付处理器,默认使用支付宝
const processor = new PaymentProcessor(new AlipayStrategy());
// 使用支付宝支付
console.log(processor.processPayment(100));
// 输出: 使用支付宝支付 100 元
// 切换到微信支付
processor.setStrategy(new WechatStrategy());
console.log(processor.processPayment(200));
// 输出: 使用微信支付 200 元
// 切换到信用卡支付
processor.setStrategy(new CreditCardStrategy());
console.log(processor.processPayment(300));
// 输出: 使用信用卡支付 300 元
}
main();
7. 命令模式
-
定义: 将请求封装为对象,支持撤销、重做等操作。
-
应用场景:
- 操作队列,如文本编辑器的撤销/重做。
- 任务调度、远程控制系统。
kotlin
// 1. 定义命令接口
interface Command {
execute(): void;
undo(): void;
}
// 2. 接收者 - 文本编辑器
class TextEditor {
private content: string = "";
append(text: string): void {
this.content += text;
console.log(`当前内容: ${this.content}`);
}
delete(length: number): void {
this.content = this.content.slice(0, -length);
console.log(`当前内容: ${this.content}`);
}
getContent(): string {
return this.content;
}
}
// 3. 具体命令类 - 添加文本命令
class AppendCommand implements Command {
private editor: TextEditor;
private text: string;
constructor(editor: TextEditor, text: string) {
this.editor = editor;
this.text = text;
}
execute(): void {
this.editor.append(this.text);
}
undo(): void {
this.editor.delete(this.text.length);
}
}
// 4. 具体命令类 - 删除文本命令
class DeleteCommand implements Command {
private editor: TextEditor;
private deletedText: string;
constructor(editor: TextEditor, length: number) {
this.editor = editor;
this.deletedText = this.editor.getContent().slice(-length);
}
execute(): void {
this.editor.delete(this.deletedText.length);
}
undo(): void {
this.editor.append(this.deletedText);
}
}
// 5. 调用者 - 命令管理器
class CommandManager {
private history: Command[] = [];
private undoStack: Command[] = [];
execute(command: Command): void {
command.execute();
this.history.push(command);
this.undoStack = []; // 每次新命令清空撤销栈
}
undo(): void {
const command = this.history.pop();
if (command) {
command.undo();
this.undoStack.push(command);
} else {
console.log("没有可撤销的操作");
}
}
redo(): void {
const command = this.undoStack.pop();
if (command) {
command.execute();
this.history.push(command);
} else {
console.log("没有可重做的操作");
}
}
}
// 6. 使用示例
function main() {
const editor = new TextEditor();
const manager = new CommandManager();
// 执行添加命令
const appendCmd1 = new AppendCommand(editor, "Hello");
manager.execute(appendCmd1); // 输出: 当前内容: Hello
const appendCmd2 = new AppendCommand(editor, " World");
manager.execute(appendCmd2); // 输出: 当前内容: Hello World
// 执行删除命令
const deleteCmd = new DeleteCommand(editor, 5);
manager.execute(deleteCmd); // 输出: 当前内容: Hello
// 撤销操作
manager.undo(); // 输出: 当前内容: Hello World
manager.undo(); // 输出: 当前内容: Hello
// 重做操作
manager.redo(); // 输出: 当前内容: Hello World
}
main();
8. 职责链模式
-
定义: 将请求沿处理者链传递,直到某个处理者处理它。
-
应用场景:
- 请求分级处理,如HTTP请求过滤器、日志级别处理。
- 解耦发送者和接收者。
scala
// 1. 定义请求接口
interface Request {
amount: number;
description: string;
}
// 2. 定义抽象处理者类
abstract class Approver {
protected next: Approver | null = null;
// 设置下一个处理者
setNext(approver: Approver): Approver {
this.next = approver;
return approver;
}
// 处理请求的抽象方法
abstract handleRequest(request: Request): void;
}
// 3. 具体处理者 - 经理
class Manager extends Approver {
handleRequest(request: Request): void {
if (request.amount <= 1000) {
console.log(`经理批准了请求: ${request.description}, 金额: ${request.amount} 元`);
} else if (this.next) {
console.log("经理无权批准,传递给下一级...");
this.next.handleRequest(request);
} else {
console.log("无更高权限处理此请求");
}
}
}
// 4. 具体处理者 - 总监
class Director extends Approver {
handleRequest(request: Request): void {
if (request.amount <= 5000) {
console.log(`总监批准了请求: ${request.description}, 金额: ${request.amount} 元`);
} else if (this.next) {
console.log("总监无权批准,传递给下一级...");
this.next.handleRequest(request);
} else {
console.log("无更高权限处理此请求");
}
}
}
// 5. 具体处理者 - CEO
class CEO extends Approver {
handleRequest(request: Request): void {
if (request.amount <= 10000) {
console.log(`CEO批准了请求: ${request.description}, 金额: ${request.amount} 元`);
} else {
console.log("金额过大,CEO也无法批准");
}
}
}
// 6. 使用示例
function main() {
// 创建处理者
const manager = new Manager();
const director = new Director();
const ceo = new CEO();
// 设置职责链: 经理 -> 总监 -> CEO
manager.setNext(director).setNext(ceo);
// 测试不同金额的请求
const request1: Request = { amount: 500, description: "购买办公用品" };
manager.handleRequest(request1);
// 输出: 经理批准了请求: 购买办公用品, 金额: 500 元
const request2: Request = { amount: 3000, description: "团队聚餐" };
manager.handleRequest(request2);
// 输出:
// 经理无权批准,传递给下一级...
// 总监批准了请求: 团队聚餐, 金额: 3000 元
const request3: Request = { amount: 15000, description: "采购服务器" };
manager.handleRequest(request3);
// 输出:
// 经理无权批准,传递给下一级...
// 总监无权批准,传递给下一级...
// 金额过大,CEO也无法批准
}
main();
9. 装饰器模式
-
定义: 动态为对象添加功能,不改变原有类结构。
-
应用场景:
- 扩展功能,如Web中间件、UI组件增强。
- 替代继承以避免类爆炸。
typescript
// 1. 定义组件接口
interface Coffee {
getDescription(): string;
getCost(): number;
}
// 2. 基础组件 - 简单咖啡
class SimpleCoffee implements Coffee {
getDescription(): string {
return "简单咖啡";
}
getCost(): number {
return 5;
}
}
// 3. 抽象装饰器类
abstract class CoffeeDecorator implements Coffee {
protected coffee: Coffee;
constructor(coffee: Coffee) {
this.coffee = coffee;
}
getDescription(): string {
return this.coffee.getDescription();
}
getCost(): number {
return this.coffee.getCost();
}
}
// 4. 具体装饰器 - 牛奶
class MilkDecorator extends CoffeeDecorator {
constructor(coffee: Coffee) {
super(coffee);
}
getDescription(): string {
return `${this.coffee.getDescription()}, 加牛奶`;
}
getCost(): number {
return this.coffee.getCost() + 2;
}
}
// 5. 具体装饰器 - 糖
class SugarDecorator extends CoffeeDecorator {
constructor(coffee: Coffee) {
super(coffee);
}
getDescription(): string {
return `${this.coffee.getDescription()}, 加糖`;
}
getCost(): number {
return this.coffee.getCost() + 1;
}
}
// 6. 使用示例
function main() {
// 基础咖啡
let coffee: Coffee = new SimpleCoffee();
console.log(`${coffee.getDescription()} - 价格: ${coffee.getCost()} 元`);
// 输出: 简单咖啡 - 价格: 5 元
// 加牛奶
coffee = new MilkDecorator(coffee);
console.log(`${coffee.getDescription()} - 价格: ${coffee.getCost()} 元`);
// 输出: 简单咖啡, 加牛奶 - 价格: 7 元
// 再加糖
coffee = new SugarDecorator(coffee);
console.log(`${coffee.getDescription()} - 价格: ${coffee.getCost()} 元`);
// 输出: 简单咖啡, 加牛奶, 加糖 - 价格: 8 元
}
main();
10. 享元模式
-
定义: 通过共享对象减少内存使用,适用于大量相似对象。
-
应用场景:
- 大量重复对象管理,如游戏中的精灵、文本编辑器中的字符渲染。
- 优化性能和内存。
typescript
// 1. 定义享元接口
interface Icon {
draw(x: number, y: number): void;
}
// 2. 享元类 - 图标
class IconFlyweight implements Icon {
private name: string; // 内在状态(共享)
constructor(name: string) {
this.name = name;
}
draw(x: number, y: number): void {
console.log(`绘制 ${this.name} 图标于位置 (${x}, ${y})`);
}
}
// 3. 享元工厂 - 管理共享对象
class IconFactory {
private icons: { [key: string]: IconFlyweight } = {};
getIcon(name: string): IconFlyweight {
if (!this.icons[name]) {
this.icons[name] = new IconFlyweight(name);
console.log(`创建新图标: ${name}`);
}
return this.icons[name];
}
getIconCount(): number {
return Object.keys(this.icons).length;
}
}
// 4. 客户端 - 使用享元
class IconRenderer {
private factory: IconFactory;
constructor(factory: IconFactory) {
this.factory = factory;
}
renderIcons(): void {
// 使用相同的图标对象在不同位置绘制
const starIcon = this.factory.getIcon("star");
starIcon.draw(10, 20);
starIcon.draw(30, 40);
const circleIcon = this.factory.getIcon("circle");
circleIcon.draw(50, 60);
const starIconAgain = this.factory.getIcon("star"); // 复用已有的 star
starIconAgain.draw(70, 80);
console.log(`总共创建的图标数量: ${this.factory.getIconCount()}`);
}
}
// 5. 使用示例
function main() {
const factory = new IconFactory();
const renderer = new IconRenderer(factory);
renderer.renderIcons();
// 输出:
// 创建新图标: star
// 绘制 star 图标于位置 (10, 20)
// 绘制 star 图标于位置 (30, 40)
// 创建新图标: circle
// 绘制 circle 图标于位置 (50, 60)
// 绘制 star 图标于位置 (70, 80)
// 总共创建的图标数量: 2
}
main();
三、资料
如果文章对你有用可以点赞收藏哦!这对我也很重要 ❤️