You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ViewModel中遵循DRY原则?优化MVVM视图模型重复代码

如何在MVVM的ViewModel转换函数中遵循DRY原则实现默认值回退?

在MVVM应用中,我们经常需要编写将原始数据(比如后端返回的entry)转换为ViewModel的函数。当未传入entry参数时,函数需要返回一套默认的回退值,但直接分情况返回两个完整对象会导致大量代码重复,违反**DRY(Don't Repeat Yourself)**原则。

优化方案:基于默认模板的对象合并

核心思路是先定义一份完整的默认ViewModel模板,当存在有效entry时,通过对象展开运算符覆盖默认值,同时处理需要特殊转换的字段(如时间格式化、数组映射、时长计算等)。这样既避免了代码重复,又能清晰区分默认值和转换逻辑。

优化后的代码如下:

import { nanoid } from 'nanoid';
import dayjs from 'dayjs';

// 定义默认的ViewModel模板
const defaultViewModel = {
    id: null,
    type: 0,
    title: null,
    slug: null,
    category: null,
    summary: null,
    content: null,
    video: null,
    duration: { 
        hours: null,
        minutes: null
    },
    createdAt: dayjs(),
    updatedAt: dayjs(),
    isHidden: false,
    isDeleted: false,
    notes: [],
    steps: [],
    keywords: [],
    covers: []
};

export default function(entry) {
    // 若无entry,直接返回默认模板的副本
    if (!entry) {
        return { ...defaultViewModel };
    }

    // 基于默认模板,覆盖entry对应的字段并处理特殊转换
    return {
        ...defaultViewModel,
        id: entry.id,
        type: entry.type ?? defaultViewModel.type,
        title: entry.title,
        slug: entry.slug,
        category: entry.category,
        summary: entry.summary,
        content: entry.body,
        video: entry.video,
        duration: entry.duration === null 
            ? defaultViewModel.duration
            : {
                hours: Math.floor(entry.duration / 60),
                minutes: entry.duration % 60
            },
        createdAt: dayjs(entry.createdAt),
        updatedAt: dayjs(entry.updatedAt),
        isHidden: entry.isHidden,
        isDeleted: entry.isDeleted,
        notes: entry.notes.map(item => ({ key: nanoid(), value: item.body })),
        steps: entry.steps.map(item => ({ key: nanoid(), value: item.body, image: item.image })),
        keywords: entry.keywords.map(item => ({ key: nanoid(), value: item.body })),
        covers: entry.covers
    };
}

关键细节说明

  • 默认模板复用:把所有字段的默认值集中定义在defaultViewModel里,避免重复编写相同的键值对。
  • 对象展开运算符:通过...defaultViewModel快速继承所有默认值,再针对有entry数据的字段进行覆盖,仅编写需要转换或替换的逻辑。
  • 空值回退处理:对于type这类可能为空的字段,使用??运算符确保当entry.type不存在时,依然保留默认值;duration字段则通过条件判断直接复用默认的时长对象。
  • 数组转换逻辑:仅在有entry时才执行数组的map转换,无entry时直接使用默认的空数组。

这种写法既保持了代码的简洁性,又符合DRY原则,后续修改字段默认值或转换逻辑时,只需在对应位置修改即可,维护成本更低。

内容的提问来源于stack exchange,提问作者Rusurano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 11:07:04