在这里插入图片描述

每日一句正能量

“不要去证明自己值得被爱,需要你拼命证明的都不是真正的爱”
真正的爱不需要考试。需要你不断交答卷、通过考核才能得到的,那不是爱,是交易。值得被爱不需要证明,因为你本来就值得。需要你削足适履去匹配的,说明那个鞋本身就不合你的脚。爱是认出你本就珍贵,不是等你证明才珍贵。

一、引言:设计模式不是银弹,但缺了它寸步难行

在 HarmonyOS ArkUI 开发中,开发者常常面临这样的困境:一个自定义组件随着需求迭代越来越臃肿,状态管理逻辑与UI渲染代码纠缠不清,多端适配代码充斥着 if-else 分支,跨组件通信通过层层回调传递导致维护成本激增。这些问题的根源往往不是技术能力不足,而是缺乏系统性的架构设计思维。

设计模式(Design Patterns)是软件工程领域经过数十年验证的解决方案模板。在 ArkUI 声明式框架下,经典设计模式并非生搬硬套,而是需要结合 ArkTS 的语言特性和 ArkUI 的响应式机制进行本土化改造。本文将系统梳理六种核心设计模式在 ArkUI 组件开发中的实战应用,涵盖组合模式、观察者模式、策略模式、工厂模式、单例模式和装饰器模式,并辅以完整的生产级代码示例。


二、ArkUI 组件设计模式全景图

在 HarmonyOS 生态中,不同的设计模式解决不同层面的架构问题:

在这里插入图片描述

设计模式 核心解决的问题 ArkUI 中的载体
组合模式 复杂组件的层级拆解与复用 @BuilderParam 插槽机制
观察者模式 状态变更的自动通知与响应 @State/@Observed/EventHub
策略模式 运行时行为切换与多端适配 策略接口 + 运行时选择器
工厂模式 动态组件创建与类型解耦 工厂函数 + 类型映射表
单例模式 全局唯一状态与资源共享 私有构造函数 + 静态实例
装饰器模式 组件能力增强与行为包装 高阶组件 + @BuilderParam

三、组合模式:组件复合与插槽机制

3.1 模式核心思想

组合模式(Composite Pattern)定义了如何将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。在 ArkUI 中,这一模式通过 @BuilderParam 插槽机制得到原生支持。

在这里插入图片描述

3.2 实战:可插槽的页面布局框架

// 定义布局组件接口
interface LayoutSlot {
  header?: () => void;
  content: () => void;
  footer?: () => void;
  sidebar?: () => void;
}

@Component
export struct PageLayout {
  @Prop title: string = '';
  @Prop showHeader: boolean = true;
  @Prop showFooter: boolean = true;
  @Prop showSidebar: boolean = false;

  // 插槽定义:使用 @BuilderParam 实现组合模式
  @BuilderParam headerBuilder: () => void = this.defaultHeader;
  @BuilderParam contentBuilder: () => void;
  @BuilderParam footerBuilder: () => void = this.defaultFooter;
  @BuilderParam sidebarBuilder: () => void = this.defaultSidebar;

  @Builder
  defaultHeader() {
    Row() {
      Text(this.title)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Blank()
      Image($r('app.media.ic_more'))
        .width(24)
        .height(24)
    }
    .width('100%')
    .height(56)
    .padding({ left: 16, right: 16 })
    .backgroundColor('#FFFFFF')
  }

  @Builder
  defaultFooter() {
    Row() {
      Text('© 2026 HarmonyOS')
        .fontSize(12)
        .fontColor('#999999')
    }
    .width('100%')
    .height(48)
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#F5F5F5')
  }

  @Builder
  defaultSidebar() {
    Column() {
      Text('侧边栏')
        .fontSize(14)
        .fontColor('#666666')
    }
    .width(200)
    .height('100%')
    .backgroundColor('#FAFAFA')
  }

  build() {
    Column() {
      if (this.showHeader) {
        this.headerBuilder();
      }

      Row() {
        if (this.showSidebar) {
          this.sidebarBuilder();
        }

        Column() {
          this.contentBuilder();
        }
        .layoutWeight(1)
        .height('100%')
      }
      .layoutWeight(1)
      .width('100%')

      if (this.showFooter) {
        this.footerBuilder();
      }
    }
    .width('100%')
    .height('100%')
  }
}

// 使用示例:不同页面复用同一布局框架
@Entry
@Component
struct HomePage {
  @Builder
  homeContent() {
    List() {
      ListItem() { Text('推荐内容1') }
      ListItem() { Text('推荐内容2') }
      ListItem() { Text('推荐内容3') }
    }
  }

  @Builder
  homeHeader() {
    Row() {
      Search({ placeholder: '搜索内容' })
        .width('80%')
      Image($r('app.media.ic_notice'))
        .width(24)
        .height(24)
    }
    .width('100%')
    .height(56)
    .padding({ left: 16, right: 16 })
  }

  build() {
    PageLayout({
      title: '首页',
      headerBuilder: this.homeHeader,
      contentBuilder: this.homeContent,
      showSidebar: false
    })
  }
}

@Entry
@Component
struct AdminPage {
  @Builder
  adminContent() {
    Grid() {
      // 管理后台仪表盘
    }
  }

  @Builder
  adminSidebar() {
    Column() {
      Text('用户管理').fontSize(14)
      Text('订单管理').fontSize(14)
      Text('数据统计').fontSize(14)
    }
    .width(200)
    .padding(16)
  }

  build() {
    PageLayout({
      title: '管理后台',
      contentBuilder: this.adminContent,
      sidebarBuilder: this.adminSidebar,
      showSidebar: true
    })
  }
}

3.3 组合模式的设计要点

  1. 统一接口:容器组件和叶子组件对外暴露一致的 @BuilderParam 接口
  2. 默认实现:为每个插槽提供默认的 @Builder 实现,降低使用门槛
  3. 条件渲染:通过布尔属性控制容器的显隐,而非在插槽内部判断
  4. 职责分离:布局逻辑在容器组件中,内容逻辑在使用方组件中

四、观察者模式:状态响应与事件驱动

4.1 模式核心思想

观察者模式(Observer Pattern)定义了对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动收到通知并更新。ArkUI 的 @State/@Observed 装饰器本身就是观察者模式的框架级实现,而 EventHub 则提供了业务层的观察者模式支持。

在这里插入图片描述

4.2 ArkUI 框架级观察者:@State 与 @Observed

@Observed
class UserProfile {
  name: string = '';
  avatar: string = '';
  level: number = 1;
  isVip: boolean = false;
}

@Component
struct UserCard {
  // @ObjectLink 建立对嵌套对象的观察
  @ObjectLink user: UserProfile;

  // 观察者:当 user 的任何属性变更时,自动重渲染
  build() {
    Row({ space: 12 }) {
      Image(this.user.avatar)
        .width(48)
        .height(48)
        .borderRadius(24)

      Column({ space: 4 }) {
        Text(this.user.name)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)

        Row({ space: 8 }) {
          Text(`Lv.${this.user.level}`)
            .fontSize(12)
            .fontColor('#999999')

          if (this.user.isVip) {
            Text('VIP')
              .fontSize(10)
              .fontColor('#FFD700')
              .backgroundColor('#FFF8E1')
              .padding({ left: 6, right: 6, top: 2, bottom: 2 })
              .borderRadius(4)
          }
        }
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(8)
  }
}

@Component
struct UserProfilePage {
  @State user: UserProfile = new UserProfile();

  aboutToAppear() {
    // 模拟异步加载用户数据
    setTimeout(() => {
      this.user.name = 'HarmonyDev';
      this.user.avatar = 'https://example.com/avatar.png';
      this.user.level = 5;
      this.user.isVip = true;
      // 所有使用 @ObjectLink 观察 user 的组件会自动刷新
    }, 1000);
  }

  build() {
    Column() {
      UserCard({ user: this.user })
      UserStats({ user: this.user })  // 另一个观察者
      UserSettings({ user: this.user })  // 又一个观察者
    }
  }
}

4.3 业务级观察者:EventHub 事件中心

// EventHub.ets —— 类型安全的事件中心
class EventHub {
  private static instance: EventHub | null = null;
  private handlers: Map<string, ((data: Object) => void)[]> = new Map();

  private constructor() {}

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

  on<T>(eventName: string, callback: (data: T) => void): () => void {
    const list = this.handlers.get(eventName) || [];
    list.push(callback as (data: Object) => void);
    this.handlers.set(eventName, list);
    return () => this.off(eventName, callback);
  }

  once<T>(eventName: string, callback: (data: T) => void): void {
    const wrapper = (data: T) => {
      callback(data);
      this.off(eventName, wrapper);
    };
    this.on(eventName, wrapper);
  }

  emit<T>(eventName: string, data?: T): void {
    const list = this.handlers.get(eventName) || [];
    list.forEach(cb => {
      try {
        cb(data as Object);
      } catch (e) {
        console.error(`[EventHub] ${eventName} handler error:`, e);
      }
    });
  }

  off<T>(eventName: string, callback: (data: T) => void): void {
    const list = this.handlers.get(eventName) || [];
    this.handlers.set(eventName, list.filter(cb => cb !== callback));
  }
}

// 使用示例:购物车跨页面通信
@Component
struct ShoppingCartBadge {
  @State badgeCount: number = 0;
  private eventHub = EventHub.getInstance();
  private unsubscribe?: () => void;

  aboutToAppear() {
    this.unsubscribe = this.eventHub.on<number>('cart:updated', (count) => {
      this.badgeCount = count;
    });
  }

  aboutToDisappear() {
    this.unsubscribe?.();
  }

  build() {
    Badge({ value: this.badgeCount.toString(), position: BadgePosition.RightTop }) {
      Image($r('app.media.ic_cart'))
        .width(28)
        .height(28)
    }
  }
}

// 商品详情页触发事件
@Component
struct ProductDetail {
  private eventHub = EventHub.getInstance();

  addToCart() {
    // 业务逻辑...
    const newCount = 3; // 假设购物车已有3件
    this.eventHub.emit('cart:updated', newCount);
  }
}

4.4 观察者模式使用约束

  1. 避免循环依赖:A 观察 B,B 观察 A 会导致无限递归通知
  2. 及时取消订阅:在 aboutToDisappear() 中清理事件监听,防止内存泄漏
  3. 控制通知粒度:避免在循环中频繁触发状态变更,使用批量更新
  4. 异常隔离:事件处理中的异常不应影响其他观察者

五、策略模式:多端适配与行为切换

5.1 模式核心思想

策略模式(Strategy Pattern)定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。在 HarmonyOS 多端适配场景中,策略模式是消除 if-else 分支的利器。

在这里插入图片描述

5.2 实战:多端布局策略

// 策略接口
interface LayoutStrategy {
  getColumns(): number;
  getGutter(): number;
  getPadding(): Padding;
  getNavPosition(): 'top' | 'bottom' | 'side';
  getFontScale(): number;
}

// 手机策略
class PhoneStrategy implements LayoutStrategy {
  getColumns(): number { return 1; }
  getGutter(): number { return 8; }
  getPadding(): Padding { return { left: 16, right: 16 }; }
  getNavPosition(): 'top' | 'bottom' | 'side' { return 'bottom'; }
  getFontScale(): number { return 1.0; }
}

// 平板策略
class TabletStrategy implements LayoutStrategy {
  getColumns(): number { return 2; }
  getGutter(): number { return 16; }
  getPadding(): Padding { return { left: 24, right: 24 }; }
  getNavPosition(): 'top' | 'bottom' | 'side' { return 'side'; }
  getFontScale(): number { return 1.1; }
}

// PC策略
class PCStrategy implements LayoutStrategy {
  getColumns(): number { return 3; }
  getGutter(): number { return 24; }
  getPadding(): Padding { return { left: 48, right: 48 }; }
  getNavPosition(): 'top' | 'bottom' | 'side' { return 'top'; }
  getFontScale(): number { return 1.0; }
}

// 车机策略
class CarStrategy implements LayoutStrategy {
  getColumns(): number { return 1; }
  getGutter(): number { return 12; }
  getPadding(): Padding { return { left: 32, right: 32 }; }
  getNavPosition(): 'top' | 'bottom' | 'side' { return 'side'; }
  getFontScale(): number { return 1.3; }  // 大字体
}

// 策略工厂
class LayoutStrategyFactory {
  private static strategies: Map<string, LayoutStrategy> = new Map([
    ['phone', new PhoneStrategy()],
    ['tablet', new TabletStrategy()],
    ['2in1', new PCStrategy()],
    ['car', new CarStrategy()],
  ]);

  static create(deviceType: string): LayoutStrategy {
    return this.strategies.get(deviceType) || new PhoneStrategy();
  }
}

// 上下文组件
@Component
export struct AdaptiveGrid {
  @State private strategy: LayoutStrategy = LayoutStrategyFactory.create(deviceInfo.deviceType);
  @Prop items: string[] = [];

  build() {
    GridRow({
      columns: this.strategy.getColumns(),
      gutter: { x: this.strategy.getGutter() }
    }) {
      ForEach(this.items, (item: string) => {
        GridCol() {
          Card({ title: item })
        }
      })
    }
    .padding(this.strategy.getPadding())
  }
}

5.3 轻量级策略:表驱动编程

当策略逻辑较简单时,可使用 Record 替代完整的策略类,避免过度设计:

// 倒计时格式策略(轻量级实现)
const timeFormatStrategies: Record<string, (h: number, m: number, s: number, ms?: number) => string> = {
  'hh:mm:ss': (h, m, s) => `${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`,
  'mm:ss': (_, m, s) => `${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`,
  'hh:mm:ss.ms': (h, m, s, ms) => `${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}.${String(ms).padStart(3,'0')}`,
};

function formatTime(format: string, hours: number, minutes: number, seconds: number, ms?: number): string {
  const strategy = timeFormatStrategies[format] || timeFormatStrategies['hh:mm:ss'];
  return strategy(hours, minutes, seconds, ms);
}

六、工厂模式:动态组件创建

6.1 模式核心思想

工厂模式(Factory Pattern)将对象的创建逻辑与使用逻辑分离。在 ArkUI 中,工厂模式常用于根据数据类型动态渲染不同的组件。

// 消息类型枚举
enum MessageType {
  TEXT = 'text',
  IMAGE = 'image',
  VIDEO = 'video',
  FILE = 'file',
  VOICE = 'voice'
}

// 消息数据接口
interface MessageData {
  id: string;
  type: MessageType;
  content: string;
  sender: string;
  timestamp: number;
}

// 组件工厂
class MessageComponentFactory {
  private static builders: Map<MessageType, (data: MessageData) => void> = new Map();

  static register(type: MessageType, builder: (data: MessageData) => void): void {
    this.builders.set(type, builder);
  }

  static create(type: MessageType, data: MessageData): (() => void) | undefined {
    return this.builders.get(type)?.bind(this, data);
  }
}

// 注册具体组件
@Component
struct TextMessage {
  @Prop data: MessageData;
  build() {
    Text(this.data.content)
      .fontSize(14)
      .padding(12)
      .backgroundColor('#E3F2FD')
      .borderRadius(8)
  }
}

@Component
struct ImageMessage {
  @Prop data: MessageData;
  build() {
    Image(this.data.content)
      .width(200)
      .height(150)
      .objectFit(ImageFit.Cover)
      .borderRadius(8)
  }
}

// 在应用入口注册
MessageComponentFactory.register(MessageType.TEXT, (data: MessageData) => { TextMessage({ data }); });
MessageComponentFactory.register(MessageType.IMAGE, (data: MessageData) => { ImageMessage({ data }); });

// 使用工厂渲染消息列表
@Component
struct MessageList {
  @Prop messages: MessageData[] = [];

  build() {
    List() {
      ForEach(this.messages, (msg: MessageData) => {
        ListItem() {
          // 根据消息类型动态创建对应组件
          if (msg.type === MessageType.TEXT) {
            TextMessage({ data: msg })
          } else if (msg.type === MessageType.IMAGE) {
            ImageMessage({ data: msg })
          }
        }
      })
    }
  }
}

七、单例模式:全局状态管理

7.1 模式核心思想

单例模式(Singleton Pattern)确保一个类只有一个实例,并提供一个全局访问点。在 ArkUI 中,单例常用于全局配置、用户会话和数据仓库。

// 全局配置中心
class AppConfig {
  private static instance: AppConfig | null = null;

  private constructor() {}

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

  // 配置属性
  apiBaseUrl: string = 'https://api.example.com';
  requestTimeout: number = 30000;
  maxRetryCount: number = 3;
  enableDebugLog: boolean = false;

  // 主题配置
  themeMode: 'light' | 'dark' | 'system' = 'system';
  fontScale: number = 1.0;

  // 初始化方法
  async initialize(): Promise<void> {
    const pref = getContext().getApplicationContext().resourceManager;
    // 从持久化存储加载配置
    this.themeMode = AppStorage.get('theme_mode') || 'system';
    this.fontScale = AppStorage.get('font_scale') || 1.0;
  }

  updateTheme(mode: 'light' | 'dark' | 'system'): void {
    this.themeMode = mode;
    AppStorage.setOrCreate('theme_mode', mode);
  }
}

// 用户会话单例
class UserSession {
  private static instance: UserSession | null = null;
  private _token: string = '';
  private _userId: string = '';
  private _isLoggedIn: boolean = false;

  private constructor() {}

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

  get token(): string { return this._token; }
  get userId(): string { return this._userId; }
  get isLoggedIn(): boolean { return this._isLoggedIn; }

  login(token: string, userId: string): void {
    this._token = token;
    this._userId = userId;
    this._isLoggedIn = true;
    // 持久化
    AppStorage.setOrCreate('auth_token', token);
  }

  logout(): void {
    this._token = '';
    this._userId = '';
    this._isLoggedIn = false;
    AppStorage.delete('auth_token');
  }
}

八、装饰器模式:高阶组件与能力增强

8.1 模式核心思想

装饰器模式(Decorator Pattern)动态地给对象添加额外的职责。在 ArkUI 中,高阶组件(HOC)是装饰器模式的典型应用。

// 定义可装饰的组件接口
interface LoadingProps {
  isLoading: boolean;
  loadingText?: string;
}

// Loading 装饰器组件
@Component
export struct WithLoading {
  @Prop isLoading: boolean = false;
  @Prop loadingText: string = '加载中...';
  @BuilderParam contentBuilder: () => void;

  build() {
    Stack() {
      this.contentBuilder();

      if (this.isLoading) {
        Column() {
          LoadingProgress()
            .width(48)
            .height(48)
            .color('#007DFF')
          Text(this.loadingText)
            .fontSize(14)
            .fontColor('#666666')
            .margin({ top: 12 })
        }
        .width('100%')
        .height('100%')
        .backgroundColor('rgba(255,255,255,0.9)')
        .justifyContent(FlexAlign.Center)
      }
    }
  }
}

// 错误边界装饰器
@Component
export struct WithErrorBoundary {
  @Prop hasError: boolean = false;
  @Prop errorMessage?: string;
  @BuilderParam contentBuilder: () => void;
  @BuilderParam fallbackBuilder?: () => void;

  @Builder
  defaultFallback() {
    Column({ space: 12 }) {
      Image($r('app.media.ic_error'))
        .width(64)
        .height(64)
      Text(this.errorMessage || '出错了,请稍后重试')
        .fontSize(14)
        .fontColor('#999999')
      Button('重新加载')
        .onClick(() => {
          // 触发重试逻辑
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  build() {
    if (this.hasError) {
      if (this.fallbackBuilder) {
        this.fallbackBuilder();
      } else {
        this.defaultFallback();
      }
    } else {
      this.contentBuilder();
    }
  }
}

// 使用装饰器组合
@Entry
@Component
struct DataPage {
  @State isLoading: boolean = true;
  @State hasError: boolean = false;
  @State data: string = '';

  aboutToAppear() {
    this.loadData();
  }

  async loadData() {
    try {
      this.isLoading = true;
      this.hasError = false;
      // 模拟异步请求
      await new Promise(resolve => setTimeout(resolve, 1500));
      this.data = '加载完成的数据';
    } catch (e) {
      this.hasError = true;
    } finally {
      this.isLoading = false;
    }
  }

  @Builder
  pageContent() {
    Column() {
      Text(this.data)
        .fontSize(16)
        .padding(24)
    }
  }

  build() {
    WithErrorBoundary({
      hasError: this.hasError,
      contentBuilder: () => {
        WithLoading({
          isLoading: this.isLoading,
          contentBuilder: this.pageContent
        })
      }
    })
  }
}

九、命令模式:撤销重做与操作队列

9.1 模式核心思想

命令模式(Command Pattern)将请求封装为对象,从而可以用不同的请求、队列或日志来参数化其他对象,同时支持可撤销的操作。

// 命令接口
interface Command {
  execute(): void;
  undo(): void;
  getDescription(): string;
}

// 具体命令:文本编辑
class TextEditCommand implements Command {
  private oldText: string;
  private newText: string;
  private target: { text: string };

  constructor(target: { text: string }, newText: string) {
    this.target = target;
    this.oldText = target.text;
    this.newText = newText;
  }

  execute(): void {
    this.target.text = this.newText;
  }

  undo(): void {
    this.target.text = this.oldText;
  }

  getDescription(): string {
    return `文本编辑: "${this.oldText}" → "${this.newText}"`;
  }
}

// 命令管理器(支持撤销重做)
class CommandManager {
  private history: Command[] = [];
  private currentIndex: number = -1;
  private maxHistory: number = 50;

  execute(command: Command): void {
    // 清除当前位置之后的历史
    if (this.currentIndex < this.history.length - 1) {
      this.history = this.history.slice(0, this.currentIndex + 1);
    }

    command.execute();
    this.history.push(command);
    this.currentIndex++;

    // 限制历史记录长度
    if (this.history.length > this.maxHistory) {
      this.history.shift();
      this.currentIndex--;
    }
  }

  undo(): boolean {
    if (this.currentIndex < 0) return false;
    this.history[this.currentIndex].undo();
    this.currentIndex--;
    return true;
  }

  redo(): boolean {
    if (this.currentIndex >= this.history.length - 1) return false;
    this.currentIndex++;
    this.history[this.currentIndex].execute();
    return true;
  }

  canUndo(): boolean {
    return this.currentIndex >= 0;
  }

  canRedo(): boolean {
    return this.currentIndex < this.history.length - 1;
  }
}

// 在组件中使用
@Component
struct TextEditor {
  @State text: string = '';
  private commandManager = new CommandManager();

  private updateText(newText: string) {
    const command = new TextEditCommand({ text: this.text }, newText);
    this.commandManager.execute(command);
    this.text = newText;  // 触发UI更新
  }

  build() {
    Column() {
      TextInput({ text: this.text })
        .onChange((value) => {
          this.updateText(value);
        })

      Row({ space: 16 }) {
        Button('撤销')
          .enabled(this.commandManager.canUndo())
          .onClick(() => {
            this.commandManager.undo();
            // 需要重新获取状态
          })

        Button('重做')
          .enabled(this.commandManager.canRedo())
          .onClick(() => {
            this.commandManager.redo();
          })
      }
    }
  }
}

十、模式融合:多模式协同实战

在实际项目中,单一设计模式往往难以满足复杂需求。以下是一个融合多种模式的综合案例——任务管理应用。

// 1. Builder 模式:任务对象构造
@Observed
class Task {
  id: string;
  title: string;
  priority: 'low' | 'medium' | 'high';
  status: 'pending' | 'completed';
  createdAt: number;

  private constructor(builder: TaskBuilder) {
    this.id = builder.id;
    this.title = builder.title;
    this.priority = builder.priority;
    this.status = builder.status;
    this.createdAt = builder.createdAt;
  }

  static builder(): TaskBuilder {
    return new TaskBuilder();
  }
}

class TaskBuilder {
  id: string = Date.now().toString();
  title: string = '';
  priority: 'low' | 'medium' | 'high' = 'medium';
  status: 'pending' | 'completed' = 'pending';
  createdAt: number = Date.now();

  setTitle(title: string): TaskBuilder { this.title = title; return this; }
  setPriority(p: 'low' | 'medium' | 'high'): TaskBuilder { this.priority = p; return this; }
  setStatus(s: 'pending' | 'completed'): TaskBuilder { this.status = s; return this; }
  build(): Task { return new Task(this); }
}

// 2. 单例模式:任务仓库
class TaskRepository {
  private static instance: TaskRepository | null = null;
  @Observed tasks: Task[] = [];
  private eventHub = EventHub.getInstance();

  private constructor() {}

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

  addTask(task: Task): void {
    this.tasks.push(task);
    this.eventHub.emit('task:added', task);
  }

  completeTask(id: string): void {
    const task = this.tasks.find(t => t.id === id);
    if (task) {
      task.status = 'completed';
      this.eventHub.emit('task:updated', task);
    }
  }
}

// 3. 策略模式:任务排序策略
interface SortStrategy {
  sort(tasks: Task[]): Task[];
}

class PrioritySortStrategy implements SortStrategy {
  sort(tasks: Task[]): Task[] {
    const priorityMap = { high: 3, medium: 2, low: 1 };
    return [...tasks].sort((a, b) => priorityMap[b.priority] - priorityMap[a.priority]);
  }
}

class TimeSortStrategy implements SortStrategy {
  sort(tasks: Task[]): Task[] {
    return [...tasks].sort((a, b) => b.createdAt - a.createdAt);
  }
}

// 4. 组合模式:任务卡片组件
@Component
struct TaskCard {
  @ObjectLink task: Task;
  @BuilderParam actionBuilder?: () => void;

  build() {
    Row() {
      Column({ space: 4 }) {
        Text(this.task.title)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
          .decoration(this.task.status === 'completed' ? TextDecorationType.LineThrough : TextDecorationType.None)

        Text(this.task.priority)
          .fontSize(12)
          .fontColor(this.task.priority === 'high' ? '#F5222D' : this.task.priority === 'medium' ? '#FAAD14' : '#52C41A')
      }
      .layoutWeight(1)
      .alignItems(HorizontalAlign.Start)

      if (this.actionBuilder) {
        this.actionBuilder();
      }
    }
    .width('100%')
    .padding(16)
    .backgroundColor(this.task.status === 'completed' ? '#F6FFED' : '#FFFFFF')
    .borderRadius(8)
  }
}

// 5. 观察者模式:任务列表自动刷新
@Component
struct TaskListPage {
  @State private repository = TaskRepository.getInstance();
  @State private sortStrategy: SortStrategy = new TimeSortStrategy();
  private eventHub = EventHub.getInstance();
  private unsubscribe?: () => void;

  aboutToAppear() {
    this.unsubscribe = this.eventHub.on('task:added', () => {
      // 触发重渲染
      this.repository = TaskRepository.getInstance();
    });
  }

  aboutToDisappear() {
    this.unsubscribe?.();
  }

  private getSortedTasks(): Task[] {
    return this.sortStrategy.sort(this.repository.tasks);
  }

  build() {
    Column() {
      Row({ space: 12 }) {
        Button('按优先级')
          .onClick(() => { this.sortStrategy = new PrioritySortStrategy(); })
        Button('按时间')
          .onClick(() => { this.sortStrategy = new TimeSortStrategy(); })
      }
      .padding(16)

      List() {
        ForEach(this.getSortedTasks(), (task: Task) => {
          ListItem() {
            TaskCard({
              task: task,
              actionBuilder: () => {
                Button('完成')
                  .enabled(task.status === 'pending')
                  .onClick(() => this.repository.completeTask(task.id))
              }
            })
          }
        })
      }
    }
  }
}

十一、设计模式使用原则

11.1 何时使用设计模式

场景特征 推荐模式 反例警示
对象构造参数超过5个且多为可选 Builder 模式 构造函数参数过长
需要全局唯一实例 单例模式 多个实例导致状态不一致
运行时切换算法/布局 策略模式 大量 if-else 分支
一对多状态通知 观察者模式 层层回调传递
动态创建不同类型组件 工厂模式 组件内直接 switch-case
给组件添加通用能力 装饰器模式 每个组件重复实现 loading/error

11.2 避免过度设计

设计模式是工具而非目的。以下情况不应强行使用设计模式:

  1. 简单场景:只有两个策略且逻辑简单,直接用 if-else 更清晰
  2. 过早抽象:需求尚未稳定时,不要为"可能的扩展"引入复杂模式
  3. 代码量激增:引入模式后代码量增加超过50%,需重新评估收益
  4. 团队认知成本:模式过于晦涩导致团队成员理解困难

11.3 模式选型检查表

  • 当前问题是否确实需要引入设计模式解决?
  • 引入后代码量变化是否在可接受范围内?
  • 团队成员是否理解该模式的核心思想?
  • 是否有更简单的替代方案(如表驱动编程)?
  • 模式引入后是否提升了可测试性?

十二、总结

HarmonyOS ArkUI 的声明式框架为设计模式的应用提供了独特的土壤:@BuilderParam 天然支持组合模式,@State/@Observed 实现了框架级观察者模式,@Component 的组件化思想与装饰器模式高度契合。开发者需要做的不是生搬硬套 GoF 的 23 种模式,而是理解每种模式要解决的核心问题,并结合 ArkTS 的语言特性进行本土化改造。

本文介绍的六种核心模式——组合、观察者、策略、工厂、单例、装饰器——覆盖了 ArkUI 开发中 80% 的架构设计场景。掌握它们的正确用法,并在适当的时机进行模式融合,是构建可维护、可扩展 HarmonyOS 应用的关键能力。


转载自:https://blog.csdn.net/u014727709/article/details/163572677
欢迎 👍点赞✍评论⭐收藏,欢迎指正

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐