普通视图

发现新文章,点击刷新页面。
昨天 — 2025年4月16日首页

UniApp金融理财产品项目简单介绍

2025年4月16日 21:51

一、项目目录架构设计

├── common                     # 公共资源
│   ├── api                    # 接口封装
│   ├── config                 # 项目配置
│   ├── filters                # 过滤器
│   ├── mixins                 # 混入
│   └── utils                  # 工具类
├── components                 # 公共组件
│   ├── risk-indicator.vue     # 风险等级指示器
│   ├── product-card.vue       # 产品卡片
│   └── secure-keyboard.vue    # 安全键盘
├── pages                      # 页面目录
│   ├── index                  # 首页
│   ├── product                # 产品模块
│   │   ├── list.vue           # 产品列表
│   │   └── detail.vue         # 产品详情
│   ├── risk                   # 风险评估
│   │   ├── questionnaire.vue  # 问卷页
│   │   └── result.vue         # 结果页
│   ├── transaction            # 交易模块
│   │   ├── purchase.vue       # 购买页
│   │   └── redeem.vue         # 赎回页
│   └── user                   # 用户模块
│       ├── login.vue          # 登录页
│       └── assets.vue         # 资产页
├── static                     # 静态资源
├── store                      # Vuex状态管理
├── uni.scss                   # 全局样式
└── manifest.json              # 应用配置

二、核心模块实现详解

1. 产品展示模块

业务流程图:

产品列表 → 筛选排序 → 进入详情 → 查看说明书 → 购买/预约

关键实现代码:

// pages/product/list.vue
export default {
  data() {
    return {
      filterParams: {
        riskLevel: '',
        yieldType: 1, // 1-固定收益 2-浮动收益
        termRange: [0, 365]
      },
      productList: []
    }
  },
  methods: {
    async loadProducts() {
      const res = await this.$api.get('/products', {
        params: this.filterParams
      })
      this.productList = res.data.map(item => ({
        ...item,
        status: this.getProductStatus(item)
      }))
    },
    getProductStatus(product) {
      // 产品状态判断逻辑
      const now = Date.now()
      if (now < product.startTime) return 'coming'
      if (product.remaining <= 0) return 'soldout'
      return 'selling'
    }
  }
}

优化点:

  • 实现分页加载和虚拟滚动‌
  • 产品卡片使用骨架屏优化体验‌
  • 收益率数字动画效果‌

2. 风险评估模块

问卷数据结构:

// store/modules/risk.js
const state = {
  questions: [
    {
      id: 'Q1',
      text: '您的年龄范围是?',
      options: [
        { text: '30岁以下', score: 5 },
        { text: '30-50岁', score: 3 },
        { text: '50岁以上', score: 1 }
      ]
    },
    // 更多问题...
  ],
  currentAnswers: {}
}

风险评估计算:

// 计算风险等级(R1-R5)
function calculateRiskLevel(answers) {
  const total = Object.values(answers).reduce((a, b) => a + b, 0)
  const levels = [
    { min: 0, max: 20, level: 'R1' },
    { min: 21, max: 40, level: 'R2' },
    // ...其他等级
  ]
  return levels.find(l => total >= l.min && total <= l.max).level
}

业务流程:

开始评估 → 逐题作答 → 提交问卷 → 显示结果 → 同步服务器 → 限制产品购买范围

3. 购买交易模块

购买流程安全验证:

// pages/transaction/purchase.vue
async submitOrder() {
  // 1. 风险等级验证
  if (this.product.riskLevel > this.userRiskLevel) {
    return this.$showModal({
      title: '风险不匹配',
      content: '该产品超出您的风险承受能力'
    })
  }
  
  // 2. 交易密码验证
  if (!await this.verifyTradePassword()) {
    return this.$toast('密码错误')
  }
  
  // 3. 创建订单
  const orderRes = await this.$api.post('/orders', {
    productId: this.product.id,
    amount: this.amount,
    clientIp: this.$getClientIP()
  })
  
  // 4. 调用支付
  uni.requestPayment({
    provider: 'wxpay',
    orderInfo: orderRes.paymentParams,
    success: () => {
      this.$trackEvent('purchase_success')
    }
  })
}

大额交易处理:

// 金额>5万的特殊验证
async verifyLargeAmount() {
  await Promise.all([
    this.verifySMSCode(),
    this.verifyFaceRecognition()
  ])
  this.$api.post('/audit/large-transaction', {
    orderId: this.orderId,
    verifyRecords: this.verifyRecords
  })
}

4. 赎回模块实现

赎回业务规则:

  • T+1到账机制‌
  • 快速赎回额度控制(单日≤1万)‌
  • 持有期限判断(是否收取赎回费)‌

关键代码:

// pages/transaction/redeem.vue
async submitRedeem() {
  // 检查是否在开放期
  if (!this.product.isInRedeemPeriod) {
    return this.$toast('当前不在可赎回时段')
  }
  
  // 快速赎回额度检查
  if (this.isFastRedeem && this.amount > 10000) {
    return this.$toast('快速赎回单日限额1万元')
  }
  
  const res = await this.$api.post('/redeem', {
    productId: this.productId,
    share: this.share,
    isFast: this.isFastRedeem
  })
  
  this.$showToast({
    title: '赎回申请成功',
    duration: 1500
  })
}

5. 用户登录模块

多因素认证流程:

// pages/user/login.vue
async handleLogin() {
  // 1. 获取微信code
  const [loginRes, settings] = await Promise.all([
    uni.login({ provider: 'weixin' }),
    uni.getSystemInfo()
  ])
  
  // 2. 调用认证接口
  const authRes = await this.$api.post('/auth/login', {
    code: loginRes.code,
    deviceId: settings.deviceId,
    platform: settings.platform
  })
  
  // 3. 生物识别验证
  if (authRes.needBioAuth) {
    await this.verifyBiometric()
  }
  
  // 4. 存储token
  uni.setStorageSync('authToken', authRes.token)
}

安全键盘实现:

<!-- components/secure-keyboard.vue -->
<template>
  <view class="keyboard-wrapper">
    <view class="keys">
      <block v-for="i in 9" :key="i">
        <view @touchstart="handleKey(i)" 
              @touchend="clearActive">
          {{i}}
        </view>
      </block>
    </view>
    <view class="shuffle" @click="shuffleKeys">
      <uni-icons type="refresh" size="20"/>
    </view>
  </view>
</template>

<script>
export default {
  methods: {
    shuffleKeys() {
      // 每次点击打乱键盘布局
      this.keyOrder = [...Array(9).keys()].sort(() => Math.random() - 0.5)
    }
  }
}
</script>

三、安全防护体系

1. 数据传输安全

// common/api/request.js
const encryptData = (data) => {
  const timestamp = Date.now()
  const nonce = Math.random().toString(36).slice(2, 10)
  return {
    encrypted: AES.encrypt(JSON.stringify(data)),
    signature: sha256(`${timestamp}${nonce}${secretKey}`),
    timestamp,
    nonce
  }
}

2. 敏感操作防护

  • 交易密码输入防截屏‌
  • 关键接口请求频率限制‌
  • 异地登录检测机制‌

3. 数据存储安全

// 使用uni-app安全存储API
uni.setStorage({
  key: 'userInfo',
  data: encrypt(userInfo),
  encrypt: true
})

四、性能优化策略

1. 首屏加载(预加载)优化

// manifest.json
{
  "preloadRule": {
    "pages/index": {
      "network": "all",
      "packages": ["__APP__"]
    }
  }
}
  1. 预加载机制原理

    • preloadRule配置允许在页面加载前预先获取关键资源‌
    • pages/index配置network: "all"表示预加载所有网络资源‌
    • packages: ["__APP__"]指定预加载主包资源‌
  2. 优化效果对比

    优化方式 传统加载 使用preloadRule
    首屏渲染时间 1.5-2s 0.8-1.2s‌
    白屏概率 较高 降低60%以上‌
    资源加载顺序 串行 并行预加载‌

二、具体优化实现方案

  1. 资源配置策略

    javascriptCopy Code
    // manifest.json 完整配置示例
    {
      "preloadRule": {
        "pages/index": {
          "network": "all",  // 预加载所有网络请求
          "packages": ["__APP__"], // 主包资源
          "pages": ["pages/detail"] // 预加载关联页面‌:ml-citation{ref="5" data="citationList"}
        }
      },
      "optimization": {
        "preloadPages": true // 启用页面预加载‌:ml-citation{ref="7" data="citationList"}
      }
    }
    

2. 资源加载优化

  • 产品图片使用WebP格式‌
  • 金融数据表格使用虚拟滚动‌
  • 非核心模块动态导入‌

3. 数据缓存策略

// 产品数据缓存示例
async getProductList() {
  const cacheKey = 'productList_' + this.filterHash
  const cached = uni.getStorageSync(cacheKey)
  if (cached && Date.now() - cached.time < 300000) {
    return cached.data
  }
  
  const freshData = await this.fetchProducts()
  uni.setStorageSync(cacheKey, {
    time: Date.now(),
    data: freshData
  })
  return freshData
}

五、多端适配方案

1. 样式适配策略

// uni.scss
.product-card {
  padding: 20rpx;
  @include respond-to('h5') {
    padding: 15px;
  }
  @include respond-to('ios') {
    border-radius: 10px;
  }
}

2. 功能差异处理

// 支付功能多端适配
function getPaymentProvider() {
  // #ifdef MP-WEIXIN
  return 'wxpay'
  // #endif
  // #ifdef APP-PLUS
  return 'applepay'
  // #endif
}

3. 组件条件编译

<!-- 安全键盘组件 -->
<!-- #ifdef APP-PLUS -->
<fingerprint-verify @success="onVerifySuccess"/>
<!-- #endif -->

六、监控与统计

1. 埋点示例

// 交易流程埋点
this.$trackEvent('purchase_start', {
  productId: this.productId,
  amount: this.amount
})

this.$trackEvent('purchase_success', {
  orderId: res.orderId,
  paymentMethod: 'wechat'
})

2. 异常监控

// 全局错误捕获
uni.onError((err) => {
  this.$api.post('/monitor/js-error', {
    msg: err.message,
    stack: err.stack,
    page: getCurrentPages().pop().route
  })
})

建议开发时特别注意:

  1. 所有金额计算必须使用Decimal.js处理‌
  2. 关键业务流程需添加水印和操作留痕‌
  3. 定期进行安全渗透测试‌
  4. 理财数据展示需标注"历史业绩不代表未来表现"‌

v2升级v3需要兼顾的几个方面

2025年4月16日 20:22

一、核心依赖升级

  1. 框架与工具链

    • Vue 核心库‌:

      npm uninstall vue && npm install vue@3.4.1  # 强制升级到最新稳定版‌
      
    • 配套库升级‌:

      npm install vue-router@4.3.2 vuex@4.1.3 @vue/test-utils@2.4.5  # 同步升级‌
      
  2. 构建工具迁移(Webpack → Vite)

    • 配置重构‌:替换 vue.config.js 为 vite.config.js,需显式声明路径别名和全局变量:

      import { defineConfig } from 'vite'
      export default defineConfig({
        resolve: { alias: { '@': '/src' } },
        define: { 'process.env': import.meta.env }  // 兼容旧环境变量写法‌
      })
      
    • 静态资源处理‌:

      // 旧写法(Webpack)
      const img = require('@/assets/logo.png')
      // 新写法(Vite)
      const img = new URL('./assets/logo.png', import.meta.url).href

二、代码层重构

  1. 组件定义变更

    • 组合式 API 替换‌:

      <!-- Vue 2(选项式) -->
      <script>
      export default {
        data() { return { count: 0 } },
        methods: { increment() { this.count++ } }
      }
      </script>
      
      <!-- Vue 3(组合式) -->
      <script setup>
      import { ref } from 'vue'
      const count = ref(0)
      const increment = () => count.value++‌
      </script>
      
  2. 生命周期钩子重命名

    Vue 2 Vue 3 触发场景
    beforeDestroy beforeUnmount 组件销毁前清理定时器/事件监听‌
    destroyed unmounted 组件已销毁后执行操作‌
  3. 全局 API 变更

    • Vue.prototype 替代‌:

      // Vue 2
      Vue.prototype.$http = axios
      
      // Vue 3
      const app = createApp(App)
      app.config.globalProperties.$http = axios‌
      
    • 过滤器(Filter)移除‌:

      vueCopy Code
      <!-- 旧写法 -->
      <div>{{ price | currency }}</div>
      <!-- 新写法 -->
      <div>{{ formatCurrency(price) }}</div>

三、生态兼容性问题

  1. UI 库迁移(Element UI → Element Plus)

    • 按需引入配置‌:

      // vite.config.js
      import Components from 'unplugin-vue-components/vite'
      import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
      export default defineConfig({
        plugins: [Components({ resolvers: [ElementPlusResolver()] })]
      })‌
      
  2. 路由系统升级(Vue Router v3 → v4)

    • 路由模式声明‌:

      // Vue 2
      new Router({ mode: 'history' })
      
      // Vue 3
      createRouter({ history: createWebHistory() })‌
      
    • 路由守卫参数变化‌:

      // Vue 2
      router.beforeEach((to, from, next) => { ... })
      
      // Vue 3
      router.beforeEach((to, from) => { ... })  // 移除 `next` 参数‌
      
  3. 状态管理(Vuex v3 → v4)

    • 模块注册变更‌:

      // Vue 2
      new Vuex.Store({ modules: { user } })
      
      // Vue 3
      createStore({ modules: { user } })‌
      

四、高频问题与解决方案

问题分类 具体问题 解决方案
模板语法 v-model 默认绑定属性变为 modelValue 显式声明绑定属性:<Child v-model:title="value" />,子组件通过 props.title 和 emit('update:title')
事件总线 Vue 3 移除 $on/$off 使用 mitt 库替代:emitter.on('event', callback)
响应式系统 Proxy 导致数组索引修改未触发更新 使用 Vue.set 或替换整个数组:list.value = [...newList]
TypeScript this 类型推断失败 使用 defineComponent 包裹组件,并显式声明类型:export default defineComponent({ ... })
第三方插件 vue-awesome-swiper 未适配 Vue 3 替换为 swiper/vue 或 @vueuse/core 的 useSwiper

五、渐进式迁移策略

  1. 混合模式过渡

    • 兼容构建‌:通过 @vue/compat 允许新旧代码共存:

      // vite.config.js
      import vue from '@vitejs/plugin-vue'
      export default defineConfig({
        plugins: [vue({ template: { compatConfig: { MODE: 2 } } })]
      })‌
      
  2. 分模块升级优先级

    优先级 模块类型 示例
    1 工具函数/工具类 日期格式化、请求封装
    2 基础组件 Button、Input 等无状态组件
    3 业务页面 订单页、用户详情页等复杂逻辑页面‌
  3. 自动化检测工具

    • ESLint 规则‌:安装 eslint-plugin-vue 检测废弃 API‌
    • 迁移助手‌:运行 vue-migration-helper 扫描代码库‌

六、迁移后验证

  1. 功能测试

    • 核心场景‌:表单提交、路由跳转、状态管理、异步请求
    • 边界案例‌:大数据量列表渲染、SSR 兼容性、IE 降级方案(如有)‌
  2. 性能监控

    • 关键指标‌:首屏加载时间(FCP)、JS 包体积、内存泄漏检测
    • 优化建议‌:使用 vite-plugin-compression 压缩资源‌

设计模式之------策略模式

2025年4月15日 22:52

一、什么是策略模式?

策略模式(Strategy Pattern) ‌ 是一种通过定义一系列可互换的算法,并将其封装成独立对象的设计模式。在前端开发中,它允许我们‌动态切换业务逻辑‌,避免复杂的条件判断(如 if-else 或 switch-case),提升代码的可维护性和扩展性。

核心特征:

  • 算法独立‌:每个策略封装一个独立算法
  • 动态切换‌:运行时自由替换策略
  • 去条件化‌:消除多层嵌套的条件分支

二、前端使用场景及实现示例

场景1:表单验证策略(基础场景)

需求‌:对不同输入类型(邮箱、手机号、密码)使用不同的校验规则

// 策略对象定义
const validationStrategies = {
  email: (value) => /^[^\s@]+@[^\s@]+.[^\s@]+$/.test(value),
  phone: (value) => /^1[3-9]\d{9}$/.test(value),
  password: (value) => value.length >= 6 && /\d/.test(value) && /[a-zA-Z]/.test(value)
};

// 验证上下文
function validateInput(type, value) {
  const strategy = validationStrategies[type];
  if (!strategy) throw new Error('未知验证类型');
  return strategy(value);
}

// 使用示例
console.log(validateInput('email', 'test@example.com')); // true
console.log(validateInput('password', 'weak')); // false

优化点‌:新增校验规则只需扩展 validationStrategies 对象,无需修改 validateInput 函数。


场景2:订单折扣策略(中等复杂度)

需求‌:根据不同的促销类型(满减、折扣、无优惠)计算订单价格

// 策略类定义
class DiscountStrategy {
  static FULL_REDUCTION(total) {
    return total >= 200 ? total - 50 : total;
  }

  static PERCENTAGE(total) {
    return total * 0.8;
  }

  static NONE(total) {
    return total;
  }
}

// React组件实现
function OrderCalculator({ promotionType }) {
  const [total, setTotal] = useState(0);

  const calculateFinal = () => {
    return DiscountStrategy[promotionType]?.(total) ?? total;
  };

  return (
    <div>
      <input type="number" onChange={e => setTotal(parseFloat(e.target.value))} />
      <p>最终价格: {calculateFinal()}</p>
    </div>
  );
}

// 使用示例
<OrderCalculator promotionType="PERCENTAGE" />

优化点‌:策略与UI组件解耦,促销策略变化不影响组件逻辑。


场景3:数据可视化渲染(复杂场景)

需求‌:根据数据类型动态选择图表渲染引擎(ECharts、D3.js、Canvas)

// 策略接口定义
interface ChartStrategy {
  render(data: DataSet): void;
  destroy(): void;
}

// 具体策略实现
const EChartsStrategy: ChartStrategy = {
  render(data) {
    const chart = echarts.init(document.getElementById('chart'));
    chart.setOption({/* ... */});
  },
  destroy() {
    echarts.dispose(document.getElementById('chart'));
  }
};

const D3Strategy: ChartStrategy = {
  render(data) {
    d3.select('#chart')
      .selectAll('rect')
      .data(data)
      .join('rect') 
      .attr('width', d => d.value);
  },
  destroy() {
    d3.select('#chart').selectAll('*').remove();
  }
};

// 策略上下文(Vue3实现)
const useChartRenderer = (strategy: ChartStrategy) => {
  onMounted(() => strategy.render(props.data));
  onBeforeUnmount(() => strategy.destroy());
};

// 组件调用
<template>
  <div id="chart" />
</template>

<script setup>
import { useChartRenderer } from './chartHooks';

// 根据用户配置选择引擎
const strategy = computed(() => 
  userConfig.renderEngine === 'd3' ? D3Strategy : EChartsStrategy
);

useChartRenderer(strategy.value);
</script>

优化点‌:渲染引擎实现细节被完全封装,切换策略不影响业务逻辑。


三、策略模式在前端的优势

场景类型 传统实现问题 策略模式优势
表单验证 需要多层if-else判断校验类型 通过策略对象属性直接索引
价格计算 促销逻辑与组件深度耦合 策略独立维护,支持动态热更新
数据可视化 切换渲染引擎需要重写大量代码 策略接口统一,实现即插即用

四、何时使用策略模式?

  1. 存在同类算法的多种实现‌(如不同的验证规则、计算方式)
  2. 需要动态切换算法‌(如用户选择不同的展示方式)
  3. 需要隔离复杂算法逻辑‌(如图表渲染引擎封装)

经典应用案例:

  • 国际化(根据语言选择翻译策略)
  • 权限校验(不同用户角色对应不同校验规则)
  • 文件上传(阿里云OSS、腾讯云COS等不同云存储切换)

五、实现要点

  1. 定义清晰的策略接口‌(TypeScript接口最佳)
  2. 使用对象字面量或类统一管理策略
  3. 通过工厂模式动态创建策略‌(可选)
  4. 结合依赖注入控制策略生命周期‌(推荐在框架中使用)
// 策略工厂示例
const strategyFactory = (type) => {
  const strategies = {
    A: StrategyA,
    B: StrategyB
  };
  return strategies[type] || DefaultStrategy;
};

六、与相似模式对比

模式 区别
工厂模式 关注对象创建,策略模式关注行为选择
状态模式 状态变化驱动行为,策略主动选择
装饰器模式 动态添加功能,策略模式替换整体算法

通过策略模式,前端开发者可以构建更灵活、更易维护的应用程序。特别是在现代前端框架(React/Vue)的组件化开发中,合理使用策略模式能显著提升复杂业务场景下的代码质量

昨天以前首页

设计模式之------单例模式

2025年4月13日 23:19

单例模式的意义

单例模式(Singleton Pattern)是一种设计模式,其核心思想是确保一个类仅有一个实例,并提供全局访问点。它的意义包括:

  1. 资源优化‌:避免重复创建对象,节省内存和计算资源。
  2. 数据一致性‌:全局共享同一个实例,避免多实例导致状态不一致。
  3. 集中管理‌:适用于全局状态、共享资源或需要统一控制的场景(如配置管理、日志记录)。

使用场景

  1. 全局状态管理‌(如 Redux Store)。
  2. 共享组件‌(如模态框、提示框)。
  3. 工具类‌(如日志记录器、缓存管理)。

代码示例与详细讲解

示例 1:全局状态管理器

class Store {
  static instance = null;

  // 通过静态方法获取单例
  static getInstance() {
    if (!Store.instance) {
      Store.instance = new Store();
    }
    return Store.instance;
  }

  constructor() {
    if (Store.instance) {
      throw new Error("Use Store.getInstance() instead of direct instantiation.");
    }
    this.state = {}; // 全局状态
  }

  // 更新状态
  setState(key, value) {
    this.state[key] = value;
  }

  // 获取状态
  getState(key) {
    return this.state[key];
  }
}

// 使用示例
const store1 = Store.getInstance();
const store2 = Store.getInstance();
console.log(store1 === store2); // true(证明是同一个实例)

store1.setState("user", "Alice");
console.log(store2.getState("user")); // "Alice"

讲解‌:

  • 通过 Store.getInstance() 获取单例,确保全局唯一。
  • 直接调用 new Store() 会抛出错误,防止误用。
  • 适用于需要统一管理全局状态的场景(如用户信息、主题配置)。

示例 2:模态框组件

class Modal {
  static instance = null;

  static getInstance() {
    if (!Modal.instance) {
      Modal.instance = new Modal();
    }
    return Modal.instance;
  }

  constructor() {
    if (Modal.instance) {
      throw new Error("Modal instance already exists.");
    }
    // 创建模态框 DOM 元素
    this.element = document.createElement("div");
    this.element.innerHTML = `
      <div class="modal" style="display: none;">
        <p>This is a modal!</p>
        <button>Close</button>
      </div>
    `;
    document.body.appendChild(this.element);
  }

  show() {
    this.element.style.display = "block";
  }

  hide() {
    this.element.style.display = "none";
  }
}

// 使用示例
const modal1 = Modal.getInstance();
const modal2 = Modal.getInstance();
console.log(modal1 === modal2); // true

modal1.show(); // 显示模态框
modal2.hide(); // 隐藏同一个模态框

讲解‌:

  • 模态框的 DOM 元素只需创建一次,避免重复渲染。
  • 通过单例确保全局只有一个模态框实例,防止页面中出现多个弹窗。
  • 适用于提示框、对话框等需要全局唯一组件的场景。

示例 3:日志记录器

class Logger {
  static instance = null;

  static getInstance() {
    if (!Logger.instance) {
      Logger.instance = new Logger();
    }
    return Logger.instance;
  }

  constructor() {
    if (Logger.instance) {
      throw new Error("Logger instance already exists.");
    }
    this.logs = [];
  }

  log(message) {
    const timestamp = new Date().toISOString();
    this.logs.push({ message, timestamp });
    console.log(`[${timestamp}] LOG: ${message}`);
  }

  printLogHistory() {
    console.log("Log History:");
    this.logs.forEach(entry => console.log(`[${entry.timestamp}] ${entry.message}`));
  }
}

// 使用示例
const logger1 = Logger.getInstance();
const logger2 = Logger.getInstance();
logger1.log("User logged in"); // [时间戳] LOG: User logged in
logger2.log("Data fetched");   // [时间戳] LOG: Data fetched
logger1.printLogHistory(); // 输出两条日志记录

讲解‌:

  • 所有日志通过同一个实例记录,便于统一处理(如上传到服务器)。
  • 避免每次记录日志时创建新实例的开销。
  • 适用于需要集中管理日志、缓存、性能监控等工具类场景。

单例模式通过限制类的实例化次数,确保全局唯一性,适用于以下场景:

  1. 资源敏感型对象‌(如数据库连接池)。
  2. 需要共享状态的组件‌(如全局 Store)。
  3. 频繁访问的工具类‌(如日志记录器)。

设计模式之--------工厂模式

2025年4月12日 23:31

一、定义与核心思想

工厂模式‌是一种创建型设计模式,用于‌封装对象的创建过程‌。其核心在于‌将对象的实例化逻辑与使用逻辑分离‌,客户端无需关心具体实现类,只需通过统一接口获取对象,实现‌解耦‌与‌扩展性‌。


二、使用场景

  1. 动态创建对象‌:根据运行时条件(如配置、用户输入)决定创建哪种对象。
  2. 隐藏复杂构造逻辑‌:对象初始化步骤较多或依赖外部资源时(如数据库连接)。
  3. 统一产品族创建‌:需要确保一组相关对象(如同一主题的UI组件)兼容使用时。

三、代码示例

示例1:简单工厂模式(汽车工厂)

场景‌:根据用户选择的车型动态创建汽车对象。

// 汽车基类
class Car {
  drive() {
    throw new Error("必须实现 drive 方法");
  }
}

// 具体产品类
class Sedan extends Car {
  drive() {
    console.log("驾驶轿车,平稳省油");
  }
}

class SUV extends Car {
  drive() {
    console.log("驾驶SUV,动力强劲");
  }
}

// 简单工厂
class CarFactory {
  static createCar(type) {
    switch (type) {
      case 'sedan':
        return new Sedan();
      case 'suv':
        return new SUV();
      default:
        throw new Error(`未知车型: ${type}`);
    }
  }
}

// 使用
const car1 = CarFactory.createCar('sedan');
car1.drive(); // 输出: 驾驶轿车,平稳省油

const car2 = CarFactory.createCar('suv');
car2.drive(); // 输出: 驾驶SUV,动力强劲
示例2:抽象工厂模式(跨平台UI组件)

场景‌:为不同操作系统(Windows/Mac)创建风格一致的UI组件。

// 抽象产品接口
class Button {
  render() {}
}

class TextBox {
  render() {}
}

// Windows 产品族
class WindowsButton extends Button {
  render() {
    return "<button class='windows-btn'>Windows按钮</button>";
  }
}

class WindowsTextBox extends TextBox {
  render() {
    return "<input type='text' class='windows-text'>";
  }
}

// Mac 产品族
class MacButton extends Button {
  render() {
    return "<button class='mac-btn'>Mac按钮</button>";
  }
}

class MacTextBox extends TextBox {
  render() {
    return "<input type='text' class='mac-text'>";
  }
}

// 抽象工厂接口
class UIFactory {
  createButton() {}
  createTextBox() {}
}

// 具体工厂类
class WindowsUIFactory extends UIFactory {
  createButton() {
    return new WindowsButton();
  }
  createTextBox() {
    return new WindowsTextBox();
  }
}

class MacUIFactory extends UIFactory {
  createButton() {
    return new MacButton();
  }
  createTextBox() {
    return new MacTextBox();
  }
}

// 客户端代码
function createUI(factory) {
  const button = factory.createButton();
  const textBox = factory.createTextBox();
  console.log(button.render(), textBox.render());
}

// 根据操作系统选择工厂
const os = 'mac'; // 可从配置读取
const factory = os === 'windows' ? new WindowsUIFactory() : new MacUIFactory();
createUI(factory);
// 输出Mac风格按钮和文本框

四、核心意义

  1. 解耦创建与使用
    客户端代码无需硬编码具体类名(如new Sedan()),只需通过工厂接口获取对象,降低模块间耦合。
  2. 集中管理创建逻辑
    当对象初始化需要复杂步骤(如读取配置、连接数据库)时,所有逻辑封装在工厂中,避免代码重复。
  3. 扩展性增强
    新增产品类型时(如新增HybridCar),只需扩展工厂类,无需修改客户端代码,符合‌开闭原则‌。
  4. 产品族一致性
    抽象工厂确保同一系列产品(如Windows风格组件)兼容协作,避免风格混用问题。

五、适用场景对比

场景类型 简单工厂 抽象工厂
适用场景 单一产品类型动态创建(如日志、汽车) 多系列产品族创建(如跨平台UI、主题换肤)
扩展方式 修改工厂类的switchif逻辑 新增具体工厂类(如LinuxUIFactory
复杂度

工厂模式通过‌封装变化点‌,将易变的对象创建逻辑隔离,使得系统更灵活、更易维护。在以下情况优先考虑使用:

  1. 系统中存在频繁变动的对象类型
  2. 需要统一管理资源(如数据库连接池)
  3. 产品之间存在强关联性(如UI主题一致性)

项目基础搭建时的一些基本注意点

2025年4月11日 23:28

一、大型项目搭建要点

  1. 架构设计与技术选型

    • 核心原则‌:强扩展性、可持续维护性、技术生态成熟度。

    • 典型方案‌:

      • 采用‌微前端架构‌(如qiankun),支持多团队并行开发与独立部署‌;
      • 技术栈选择‌React/Vue3+TypeScript‌,搭配‌Webpack/Vite‌构建工具,确保长期生态支持‌;
      • 集成‌SSR(服务端渲染) ‌提升SEO和首屏性能,如Next.js/Nuxt.js‌。
    • 案例‌:某金融平台项目采用微前端+React+TS架构,支持5年内新增10+业务模块,代码复用率达60%‌。

  2. 开发流程与规范

    • 代码质量管控‌:

      • 强制‌ESLint/Prettier‌规范,结合‌Git Hooks‌拦截不规范提交‌;
      • 建立‌组件库‌(如Storybook),统一UI交互逻辑,降低重复开发成本‌。
    • 分支管理‌:

      • 采用‌GitFlow‌模式,定义feature(功能分支)、release(预发布分支)等流程‌。
  3. 长期维护策略

    • 模块化拆分‌:按业务域划分模块(如支付、风控),通过‌Monorepo‌管理依赖‌;
    • 自动化运维‌:搭建‌CI/CD流水线‌(如Jenkins),支持灰度发布和回滚机制‌。

二、中短期项目(7-8个月周期)搭建要点

  1. 敏捷开发与快速交付

    • 技术选型‌:

      • 选择‌轻量框架‌(如Vite+React),减少配置成本‌;
      • 集成‌低代码平台‌(如amis),实现表单/列表页快速生成‌。
    • 案例‌:某政务H5项目采用Vite+预置模板,2周完成核心功能开发,节省30%工时‌。

  2. 需求管理与风险控制

    • 需求冻结机制‌:在开发中期设置‌需求评审截止点‌,避免范围蔓延‌;
    • 动态资源配置‌:使用‌甘特图工具‌(如Jira)可视化进度,及时调整人力分配‌。
  3. 代码复用与灵活扩展

    • 脚手架定制‌:预置‌axios封装、权限模块、错误监控‌等基础能力‌;
    • 动态配置化‌:通过JSON驱动页面布局(如动态表单生成器),支持快速迭代‌。

三、通用核心注意点

  1. 团队协作优化

    • 角色分工‌:明确前端开发、UI协作、测试验收流程(如Figma标注自动生成代码)‌;
    • 知识沉淀‌:建立‌Confluence文档库‌,记录技术决策与踩坑记录‌。
  2. 性能与兼容性

    • 基线要求‌:

      • 兼容Chrome/Firefox/Edge最新3个版本‌;
      • 首屏加载时间≤1.5秒(3G网络)‌。
    • 监控体系‌:集成‌Sentry‌错误追踪+‌Lighthouse‌性能评分‌。

  3. 安全防护

    • XSS/CSRF防御‌:对用户输入内容强制过滤(如DOMPurify)‌;
    • 敏感操作验证‌:关键接口增加二次确认(如短信验证码)‌。

典型项目周期对比表

维度 大型项目(5-6年) 中短期项目(7-8个月)
技术选型 React/Vue3+TS+微前端 Vite+轻量框架+低代码
构建工具 Webpack(定制化配置) Vite(开箱即用)
代码规范 企业级ESLint规则+Monorepo 社区标准规则+快速模板
测试策略 单元测试+集成测试+E2E 核心路径E2E测试
部署频率 按月发布(灰度策略) 按周发布(敏捷迭代)
❌
❌