您现在的位置是:网站首页 > 可持续编程中的模式考量文章详情
可持续编程中的模式考量
陈川
【
JavaScript
】
34417人已围观
9961字
可持续编程中的模式考量
编程模式的选择直接影响代码的可维护性、可扩展性和可读性。在JavaScript生态中,设计模式的应用能够帮助开发者构建更健壮的系统,特别是在长期维护和多人协作的场景下。合理的模式选择需要考虑项目规模、团队习惯以及未来可能的变化方向。
单例模式与全局状态管理
单例模式在JavaScript中常用于管理全局状态,但过度使用可能导致代码耦合度增加。现代前端框架通常推荐使用专门的状态管理库,但在某些场景下,单例仍然有其价值。
class AppConfig {
constructor() {
if (AppConfig.instance) {
return AppConfig.instance
}
this.apiEndpoint = 'https://api.example.com'
this.theme = 'dark'
AppConfig.instance = this
}
}
// 使用示例
const config1 = new AppConfig()
const config2 = new AppConfig()
console.log(config1 === config2) // true
这种实现方式确保了配置对象的唯一性,但需要注意在测试环境中可能需要重置实例。更现代的替代方案是使用模块系统的天然单例特性:
// config.js
export const config = {
apiEndpoint: 'https://api.example.com',
theme: 'dark'
}
工厂模式与组件创建
工厂模式在UI组件创建中特别有用,尤其是当需要根据不同类型或条件创建相似但略有差异的组件时。
class ButtonFactory {
createButton(type) {
switch(type) {
case 'primary':
return new PrimaryButton()
case 'secondary':
return new SecondaryButton()
case 'icon':
return new IconButton()
default:
throw new Error('Unknown button type')
}
}
}
class PrimaryButton {
render() {
return '<button class="btn btn-primary">...</button>'
}
}
在React等框架中,这种模式可以演变为组件映射:
const componentMap = {
alert: AlertComponent,
card: CardComponent,
modal: ModalComponent
}
function DynamicRenderer({ type, props }) {
const Component = componentMap[type]
return <Component {...props} />
}
观察者模式与事件驱动架构
观察者模式是实现松耦合组件通信的有效方式,特别适合需要多个独立部分响应同一事件变化的场景。
class EventBus {
constructor() {
this.subscribers = {}
}
subscribe(event, callback) {
if (!this.subscribers[event]) {
this.subscribers[event] = []
}
this.subscribers[event].push(callback)
}
publish(event, data) {
if (this.subscribers[event]) {
this.subscribers[event].forEach(callback => callback(data))
}
}
}
// 使用示例
const bus = new EventBus()
bus.subscribe('userLoggedIn', (user) => {
console.log(`User ${user.name} logged in`)
})
在大型应用中,这种模式可以扩展为更精细的领域事件系统,每个模块只关心与自己相关的事件。
策略模式与算法封装
策略模式允许在运行时选择不同的算法或行为,特别适合需要根据不同条件应用不同业务规则的场景。
class PaymentProcessor {
constructor(strategy) {
this.strategy = strategy
}
process(amount) {
return this.strategy.execute(amount)
}
}
class CreditCardStrategy {
execute(amount) {
console.log(`Processing $${amount} via Credit Card`)
// 实际的支付处理逻辑
}
}
class PayPalStrategy {
execute(amount) {
console.log(`Processing $${amount} via PayPal`)
// 实际的支付处理逻辑
}
}
// 使用示例
const processor = new PaymentProcessor(new CreditCardStrategy())
processor.process(100)
在函数式编程风格中,策略模式可以简化为简单的函数组合:
const strategies = {
creditCard: amount => { /*...*/ },
paypal: amount => { /*...*/ },
crypto: amount => { /*...*/ }
}
function processPayment(strategyType, amount) {
return strategies[strategyType](amount)
}
装饰器模式与功能扩展
装饰器模式提供了一种灵活的方式来扩展对象功能,而无需修改原始类。在JavaScript中,高阶函数和类装饰器都是这种模式的体现。
function withLogging(fn) {
return function(...args) {
console.log(`Calling function with args: ${args}`)
const result = fn.apply(this, args)
console.log(`Function returned: ${result}`)
return result
}
}
// 使用示例
const calculate = (a, b) => a + b
const loggedCalculate = withLogging(calculate)
loggedCalculate(2, 3)
在ES2016+中,可以使用类装饰器语法:
@logDecorator
class Calculator {
add(a, b) {
return a + b
}
}
function logDecorator(target) {
const originalMethods = Object.getOwnPropertyNames(target.prototype)
originalMethods.forEach(method => {
if (method !== 'constructor') {
const original = target.prototype[method]
target.prototype[method] = function(...args) {
console.log(`Calling ${method} with`, args)
const result = original.apply(this, args)
console.log(`Method ${method} returned`, result)
return result
}
}
})
return target
}
模块模式与代码组织
模块模式是JavaScript中最基础也最重要的模式之一,它帮助开发者组织代码并控制可见性。现代JavaScript使用ES模块系统,但理解其原理仍然有价值。
const counterModule = (() => {
let count = 0
const increment = () => {
count++
console.log(count)
}
const reset = () => {
count = 0
console.log('Counter reset')
}
return {
increment,
reset
}
})()
// 使用示例
counterModule.increment() // 1
counterModule.increment() // 2
counterModule.reset() // Counter reset
在TypeScript中,可以利用接口进一步明确模块的契约:
interface CounterModule {
increment(): void
reset(): void
}
const counterModule: CounterModule = (() => {
// 实现同上
})()
中间件模式与请求处理
中间件模式在处理管道或链式操作中非常常见,特别是在服务器端框架和某些客户端状态管理中。
function createMiddlewarePipeline() {
const middlewares = []
const use = (fn) => {
middlewares.push(fn)
}
const execute = (context) => {
let index = 0
const next = () => {
if (index < middlewares.length) {
const middleware = middlewares[index++]
return middleware(context, next)
}
}
return next()
}
return { use, execute }
}
// 使用示例
const pipeline = createMiddlewarePipeline()
pipeline.use((ctx, next) => {
console.log('Middleware 1 start')
next()
console.log('Middleware 1 end')
})
pipeline.use((ctx, next) => {
console.log('Middleware 2 start')
next()
console.log('Middleware 2 end')
})
pipeline.execute({})
这种模式在Express、Koa等框架中广泛使用,理解其原理有助于编写更高效的中间件。
组合模式与UI树结构
组合模式适用于表示部分-整体层次结构,使得客户端可以统一处理单个对象和组合对象。在前端开发中,UI组件树就是典型的组合模式应用。
const Component = ({ name, children }) => (
<div className="component">
<h3>{name}</h3>
<div className="children">
{children}
</div>
</div>
)
// 使用示例
const App = () => (
<Component name="Root">
<Component name="Child 1">
<Component name="Grandchild 1" />
<Component name="Grandchild 2" />
</Component>
<Component name="Child 2" />
</Component>
)
在纯JavaScript中实现组合模式:
class UIComponent {
constructor(name) {
this.name = name
this.children = []
}
add(child) {
this.children.push(child)
}
render() {
console.log(`Rendering ${this.name}`)
this.children.forEach(child => child.render())
}
}
// 使用示例
const root = new UIComponent('Root')
const child1 = new UIComponent('Child 1')
const child2 = new UIComponent('Child 2')
root.add(child1)
root.add(child2)
child1.add(new UIComponent('Grandchild 1'))
child1.add(new UIComponent('Grandchild 2'))
root.render()
代理模式与操作控制
代理模式为其他对象提供一种代理以控制对这个对象的访问。在前端中,常用于缓存、验证或延迟初始化等场景。
class ImageLoader {
constructor(url) {
this.url = url
}
load() {
console.log(`Loading image from ${this.url}`)
return `Image data from ${this.url}`
}
}
class ImageProxy {
constructor(url) {
this.url = url
this.imageLoader = null
this.cachedImage = null
}
load() {
if (this.cachedImage) {
console.log('Returning cached image')
return this.cachedImage
}
if (!this.imageLoader) {
this.imageLoader = new ImageLoader(this.url)
}
this.cachedImage = this.imageLoader.load()
return this.cachedImage
}
}
// 使用示例
const proxy = new ImageProxy('example.com/image.jpg')
proxy.load() // 实际加载
proxy.load() // 返回缓存
在JavaScript中,Proxy对象提供了语言级别的代理实现:
const target = {
message: 'hello',
getMessage() {
return this.message
}
}
const handler = {
get(target, prop, receiver) {
if (prop === 'message') {
console.log('Accessing message property')
}
return Reflect.get(...arguments)
}
}
const proxy = new Proxy(target, handler)
console.log(proxy.message) // 日志 + 'hello'
状态模式与复杂状态管理
状态模式允许对象在其内部状态改变时改变它的行为,这在管理复杂UI状态时特别有用。
class Order {
constructor() {
this.state = new PendingState(this)
}
changeState(state) {
this.state = state
}
proceed() {
this.state.proceed()
}
}
class OrderState {
constructor(order) {
this.order = order
}
proceed() {
throw new Error('Method not implemented')
}
}
class PendingState extends OrderState {
proceed() {
console.log('Processing payment...')
this.order.changeState(new PaidState(this.order))
}
}
class PaidState extends OrderState {
proceed() {
console.log('Preparing shipment...')
this.order.changeState(new ShippedState(this.order))
}
}
// 使用示例
const order = new Order()
order.proceed() // Processing payment...
order.proceed() // Preparing shipment...
在React中,状态模式可以与hooks结合:
function useOrderState() {
const [state, setState] = useState('pending')
const states = {
pending: {
proceed: () => {
console.log('Processing payment...')
setState('paid')
}
},
paid: {
proceed: () => {
console.log('Preparing shipment...')
setState('shipped')
}
}
}
return states[state]
}
依赖注入与可测试性
依赖注入模式通过外部传入依赖项来提高代码的可测试性和灵活性,而不是在内部硬编码依赖关系。
class UserService {
constructor(userRepository, logger) {
this.userRepository = userRepository
this.logger = logger
}
getUser(id) {
this.logger.log(`Fetching user ${id}`)
return this.userRepository.getById(id)
}
}
// 使用示例
const fakeUserRepository = {
getById: id => ({ id, name: 'Test User' })
}
const consoleLogger = {
log: message => console.log(message)
}
const userService = new UserService(fakeUserRepository, consoleLogger)
userService.getUser(1)
在现代前端框架中,依赖注入通常通过上下文API或专门的DI容器实现:
const ServicesContext = React.createContext()
function App() {
const services = {
userService: new UserService(),
productService: new ProductService()
}
return (
<ServicesContext.Provider value={services}>
<UserProfile />
</ServicesContext.Provider>
)
}
function UserProfile() {
const { userService } = useContext(ServicesContext)
// 使用userService
}
上一篇: 设计模式与元宇宙开发