Loading...
Loading...
Compare original and translation side by side
// ❌ Logic buried in larger method
function processOrder(order: Order) {
// ... 20 lines of setup ...
// Validate payment
if (order.payment.amount <= 0) {
throw new Error("Amount must be positive");
}
if (!order.payment.cardToken) {
throw new Error("Card required");
}
if (order.payment.amount > order.payment.cardLimit) {
throw new Error("Exceeds card limit");
}
// ... 20 more lines ...
}// ❌ 逻辑嵌套在大型方法中
function processOrder(order: Order) {
// ... 20行初始化代码 ...
// Validate payment
if (order.payment.amount <= 0) {
throw new Error("Amount must be positive");
}
if (!order.payment.cardToken) {
throw new Error("Card required");
}
if (order.payment.amount > order.payment.cardLimit) {
throw new Error("Exceeds card limit");
}
// ... 另外20行代码 ...
}// ✅ Validation isolated and reusable
function processOrder(order: Order) {
// ... setup ...
validatePayment(order.payment);
// ... rest of logic ...
}
function validatePayment(payment: Payment) {
if (payment.amount <= 0) {
throw new Error("Amount must be positive");
}
if (!payment.cardToken) {
throw new Error("Card required");
}
if (payment.amount > payment.cardLimit) {
throw new Error("Exceeds card limit");
}
}// ✅ 校验逻辑被隔离且可复用
function processOrder(order: Order) {
// ... 初始化代码 ...
validatePayment(order.payment);
// ... 剩余逻辑 ...
}
function validatePayment(payment: Payment) {
if (payment.amount <= 0) {
throw new Error("Amount must be positive");
}
if (!payment.cardToken) {
throw new Error("Card required");
}
if (payment.amount > payment.cardLimit) {
throw new Error("Exceeds card limit");
}
}// ❌ Mixed concerns in one class
class Order {
id: string;
customerId: string;
items: OrderItem[];
// Address fields scattered
shippingStreet: string;
shippingCity: string;
shippingZip: string;
billingStreet: string;
billingCity: string;
billingZip: string;
getShippingAddress(): string { /* ... */ }
getBillingAddress(): string { /* ... */ }
updateShippingAddress(street, city, zip) { /* ... */ }
validateShippingAddress() { /* ... */ }
calculateShippingCost() { /* ... */ }
}// ❌ 单个类混杂了多个职责
class Order {
id: string;
customerId: string;
items: OrderItem[];
// 地址字段分散
shippingStreet: string;
shippingCity: string;
shippingZip: string;
billingStreet: string;
billingCity: string;
billingZip: string;
getShippingAddress(): string { /* ... */ }
getBillingAddress(): string { /* ... */ }
updateShippingAddress(street, city, zip) { /* ... */ }
validateShippingAddress() { /* ... */ }
calculateShippingCost() { /* ... */ }
}// ✅ Address responsibility extracted
class Address {
street: string;
city: string;
zip: string;
validate(): void { /* ... */ }
toString(): string { /* ... */ }
}
class Order {
id: string;
customerId: string;
items: OrderItem[];
shippingAddress: Address;
billingAddress: Address;
calculateShippingCost(): void { /* ... */ }
}// ✅ 地址相关职责被抽取出来
class Address {
street: string;
city: string;
zip: string;
validate(): void { /* ... */ }
toString(): string { /* ... */ }
}
class Order {
id: string;
customerId: string;
items: OrderItem[];
shippingAddress: Address;
billingAddress: Address;
calculateShippingCost(): void { /* ... */ }
}// ❌ Type-based conditionals scattered
function calculateDiscount(customer: Customer): number {
if (customer.type === "gold") {
return customer.totalSpent * 0.15;
} else if (customer.type === "silver") {
return customer.totalSpent * 0.10;
} else if (customer.type === "bronze") {
return customer.totalSpent * 0.05;
}
return 0;
}
function sendNotification(customer: Customer, message: string) {
if (customer.type === "gold") {
sendEmail(customer.email, message);
sendSMS(customer.phone, message);
} else if (customer.type === "silver") {
sendEmail(customer.email, message);
} else {
// bronze gets nothing
}
}// ❌ 基于类型的条件判断分散在各处
function calculateDiscount(customer: Customer): number {
if (customer.type === "gold") {
return customer.totalSpent * 0.15;
} else if (customer.type === "silver") {
return customer.totalSpent * 0.10;
} else if (customer.type === "bronze") {
return customer.totalSpent * 0.05;
}
return 0;
}
function sendNotification(customer: Customer, message: string) {
if (customer.type === "gold") {
sendEmail(customer.email, message);
sendSMS(customer.phone, message);
} else if (customer.type === "silver") {
sendEmail(customer.email, message);
} else {
// bronze等级用户不接收通知
}
}// ✅ Each customer type knows its own behavior
interface Customer {
name: string;
totalSpent: number;
calculateDiscount(): number;
sendNotification(message: string): void;
}
class GoldCustomer implements Customer {
calculateDiscount(): number {
return this.totalSpent * 0.15;
}
sendNotification(message: string): void {
sendEmail(this.email, message);
sendSMS(this.phone, message);
}
}
class SilverCustomer implements Customer {
calculateDiscount(): number {
return this.totalSpent * 0.10;
}
sendNotification(message: string): void {
sendEmail(this.email, message);
}
}
class BronzeCustomer implements Customer {
calculateDiscount(): number {
return this.totalSpent * 0.05;
}
sendNotification(message: string): void {
// intentionally does nothing
}
}
// Call site is now simple
const discount = customer.calculateDiscount();
customer.sendNotification(msg);// ✅ 每个客户类型管理自己的行为
interface Customer {
name: string;
totalSpent: number;
calculateDiscount(): number;
sendNotification(message: string): void;
}
class GoldCustomer implements Customer {
calculateDiscount(): number {
return this.totalSpent * 0.15;
}
sendNotification(message: string): void {
sendEmail(this.email, message);
sendSMS(this.phone, message);
}
}
class SilverCustomer implements Customer {
calculateDiscount(): number {
return this.totalSpent * 0.10;
}
sendNotification(message: string): void {
sendEmail(this.email, message);
}
}
class BronzeCustomer implements Customer {
calculateDiscount(): number {
return this.totalSpent * 0.05;
}
sendNotification(message: string): void {
// intentionally does nothing
}
}
// 调用处现在非常简洁
const discount = customer.calculateDiscount();
customer.sendNotification(msg);undefinedundefinedundefinedundefinedundefinedundefined
**Payoff:** Readability improves, intent is explicit, logic can be tested separately, same condition can be reused.
---
**收益:** 可读性提升,意图明确,逻辑可单独测试,相同判断可复用。
---// ❌ Nested if/else (default case buried at end)
function calculateShipping(order: Order): ShippingCost {
if (order.weight > 0) {
if (order.destination !== null) {
if (order.isPriority) {
return calculateExpressShipping(order);
} else {
return calculateStandardShipping(order);
}
} else {
throw new Error("No destination");
}
} else {
throw new Error("Invalid weight");
}
}// ❌ 嵌套if/else(默认逻辑藏在末尾)
function calculateShipping(order: Order): ShippingCost {
if (order.weight > 0) {
if (order.destination !== null) {
if (order.isPriority) {
return calculateExpressShipping(order);
} else {
return calculateStandardShipping(order);
}
} else {
throw new Error("No destination");
}
} else {
throw new Error("Invalid weight");
}
}// ✅ Guards at top, happy path clear
function calculateShipping(order: Order): ShippingCost {
if (order.weight <= 0) {
throw new Error("Invalid weight");
}
if (!order.destination) {
throw new Error("No destination");
}
if (order.isPriority) {
return calculateExpressShipping(order);
}
return calculateStandardShipping(order);
}// ✅ 卫语句放在顶部,主流程清晰
function calculateShipping(order: Order): ShippingCost {
if (order.weight <= 0) {
throw new Error("Invalid weight");
}
if (!order.destination) {
throw new Error("No destination");
}
if (order.isPriority) {
return calculateExpressShipping(order);
}
return calculateStandardShipping(order);
}// ❌ Method belongs elsewhere
class Order {
items: OrderItem[];
customer: Customer;
// This method uses mostly customer data
calculateCustomerDiscount(): number {
if (this.customer.isPremium) {
return this.items.reduce((sum, item) => sum + item.price, 0) * 0.15;
}
return 0;
}
}// ❌ 方法所属类不对
class Order {
items: OrderItem[];
customer: Customer;
// 该方法主要使用客户数据
calculateCustomerDiscount(): number {
if (this.customer.isPremium) {
return this.items.reduce((sum, item) => sum + item.price, 0) * 0.15;
}
return 0;
}
}// ✅ Discount logic lives with customer
class Customer {
isPremium: boolean;
calculateDiscount(orderTotal: number): number {
return this.isPremium ? orderTotal * 0.15 : 0;
}
}
class Order {
items: OrderItem[];
customer: Customer;
getTotal(): number {
const subtotal = this.items.reduce((sum, item) => sum + item.price, 0);
const discount = this.customer.calculateDiscount(subtotal);
return subtotal - discount;
}
}// ✅ 折扣逻辑和客户数据放在一起
class Customer {
isPremium: boolean;
calculateDiscount(orderTotal: number): number {
return this.isPremium ? orderTotal * 0.15 : 0;
}
}
class Order {
items: OrderItem[];
customer: Customer;
getTotal(): number {
const subtotal = this.items.reduce((sum, item) => sum + item.price, 0);
const discount = this.customer.calculateDiscount(subtotal);
return subtotal - discount;
}
}calctmpdatacalctmpdata// ❌ Poor naming requires mental mapping
function proc(d: any[]): any[] {
const r = [];
for (let i = 0; i < d.length; i++) {
if (d[i].s === "active") {
r.push(d[i].amt * 1.15); // What's being calculated?
}
}
return r;
}// ❌ 糟糕的命名需要额外的心智映射
function proc(d: any[]): any[] {
const r = [];
for (let i = 0; i < d.length; i++) {
if (d[i].s === "active") {
r.push(d[i].amt * 1.15); // 这里在计算什么?
}
}
return r;
}// ✅ Intent is self-evident
function calculateTaxAdjustedAmounts(orders: Order[]): number[] {
const taxAdjustedAmounts = [];
for (const order of orders) {
if (order.status === "active") {
const taxRate = 1.15; // 15% tax
taxAdjustedAmounts.push(order.amount * taxRate);
}
}
return taxAdjustedAmounts;
}
// Even better with functional approach
function calculateTaxAdjustedAmounts(orders: Order[]): number[] {
return orders
.filter((order) => order.status === "active")
.map((order) => order.amount * 1.15);
}// ✅ 意图不言自明
function calculateTaxAdjustedAmounts(orders: Order[]): number[] {
const taxAdjustedAmounts = [];
for (const order of orders) {
if (order.status === "active") {
const taxRate = 1.15; // 15% tax
taxAdjustedAmounts.push(order.amount * taxRate);
}
}
return taxAdjustedAmounts;
}
// 用函数式写法更优
function calculateTaxAdjustedAmounts(orders: Order[]): number[] {
return orders
.filter((order) => order.status === "active")
.map((order) => order.amount * 1.15);
}| Pattern | Use When | Payoff |
|---|---|---|
| Extract Method | Logic has single purpose, appears multiple times, or is hard to test | Reusable, testable, clearer intent |
| Extract Class | Class has multiple responsibilities or mixed concerns | Focused, reusable, easier to test |
| Replace Conditional | Same type/status check scattered in multiple places | Open/Closed Principle, localized behavior, extensible |
| Introduce Variable | Complex expression is hard to read or repeated | Self-documenting, testable, reusable |
| Simplify Conditional | Nested or complex if/else logic | Readable, fail-fast, happy path clear |
| Move Method/Field | Method/field belongs logically elsewhere | Better cohesion, less coupling, reusable |
| Rename | Name doesn't express intent | Self-documenting, faster onboarding, clearer design |
| 模式 | 适用场景 | 收益 |
|---|---|---|
| 提取方法 | 逻辑有单一职责、多次出现、难以单独测试 | 可复用、可测试、意图更清晰 |
| 提取类 | 类有多个职责或混杂了不同关注点 | 职责聚焦、可复用、更易测试 |
| 替换条件判断 | 相同的类型/状态检查分散在多个位置 | 符合开闭原则、行为本地化、可扩展 |
| 引入变量 | 复杂表达式难以阅读或重复出现 | 自解释、可测试、可复用 |
| 简化条件判断 | 嵌套或复杂的if/else逻辑 | 可读性高、快速失败、主流程清晰 |
| 移动方法/字段 | 方法/字段逻辑上属于其他类 | 内聚性更高、耦合度更低、可复用 |
| 重命名 | 名称不能表达实际意图 | 代码自解释、上手更快、设计更清晰 |
refactoring-catalogrefactoring-catalog