ダイアログ管理クラスのデモ

クラスやメソッドの名前を変更し、コードをより洗練され理解しやすいものにします。

名前付け方針

DialogConfigBuilder クラス
  • DialogConfigBuilder:ダイアログ設定を構築するためのクラスです。
  • withPrimaryButton および withSecondaryButton:プライマリボタンとセカンダリボタンを設定するメソッドです。
  • withCustomOptions:カスタムダイアログコントロールオプションを設定するメソッドです。
  • buildAndShow:ダイアログを構築して表示するメソッドです。
import { DialogConfig } from '../advancedDialogConfig/DialogConfig';
import { CustomDialogControllerOptions } from '../CustomDialogOptions';
import { ButtonOptions } from '@ohos.arkui.advanced.Dialog';

@Observed
export class DialogConfigBuilder {
  private marker: string;
  private content: ResourceStr;
  private primaryButton?: ButtonOptions;
  private secondaryButton?: ButtonOptions;
  private customDialogControllerOptions?: CustomDialogControllerOptions;

  private constructor(marker: string, content: ResourceStr) {
    this.marker = marker;
    this.content = content;
  }

  public static create(marker: string, content: ResourceStr): DialogConfigBuilder {
    return new DialogConfigBuilder(marker, content);
  }

  public withPrimaryButton(primaryButton: ButtonOptions): DialogConfigBuilder {
    this.primaryButton = primaryButton;
    return this;
  }

  public withSecondaryButton(secondaryButton: ButtonOptions): DialogConfigBuilder {
    this.secondaryButton = secondaryButton;
    return this;
  }

  public withCustomOptions(customDialogControllerOptions: CustomDialogControllerOptions): DialogConfigBuilder {
    this.customDialogControllerOptions = customDialogControllerOptions;
    return this;
  }

  public build(): DialogConfig {
    return new DialogConfig(
      this.marker,
      this.content,
      this.primaryButton,
      this.secondaryButton,
      this.customDialogControllerOptions
    );
  }

  public buildAndShow(): void {
    const config = this.build();
    DialogManager.getInstance().show(config);
  }
}
import { CustomDialogControllerOptions } from '../CustomDialogOptions';
import { ButtonOptions } from '@ohos.arkui.advanced.Dialog';

@Observed
export class DialogConfig {
  marker: string;
  content: ResourceStr;
  primaryButton?: ButtonOptions;
  secondaryButton?: ButtonOptions;
  customDialogControllerOptions?: CustomDialogControllerOptions;

  constructor(
    marker: string,
    content: ResourceStr,
    primaryButton?: ButtonOptions,
    secondaryButton?: ButtonOptions,
    customDialogControllerOptions?: CustomDialogControllerOptions
  ) {
    this.marker = marker;
    this.content = content;
    this.primaryButton = primaryButton;
    this.secondaryButton = secondaryButton;
    this.customDialogControllerOptions = customDialogControllerOptions;
  }
}
import { DialogConfig } from '../advancedDialogConfig/DialogConfig';
import { UIContext } from '@ohos.arkui.UIContext';

export class DialogManager {
  private uiContext?: UIContext;

  private static instance: DialogManager;
  private dialogControllerMap: Map<string, CustomDialogController> = new Map();

  private constructor() {}

  public static getInstance(): DialogManager {
    if (!DialogManager.instance) {
      console.debug('DialogManager', 'Creating new instance');
      DialogManager.instance = new DialogManager();
    }
    return DialogManager.instance;
  }

  public setUiContext(uiContext: UIContext): void {
    if (!uiContext) {
      return;
    }
    this.uiContext = uiContext;
    console.debug('DialogManager', `UI context set: ${uiContext}`);
  }

  public setDialogController(marker: string, dialogController: CustomDialogController): void {
    if (this.dialogControllerMap.has(marker)) {
      console.debug('DialogManager', `${marker} already in map, updating`);
    }
    this.dialogControllerMap.set(marker, dialogController);
  }

  public async show(config: DialogConfig): Promise<boolean> {
    if (!this.uiContext) {
      console.debug('DialogManager', `${config.marker} UI context is not set`);
      return false;
    }
    const advancedPromptAction = this.uiContext.getPromptAction();
    if (!advancedPromptAction) {
      console.debug('DialogManager', `No prompt action found for ${config.marker}`);
      return false;
    }
    advancedPromptAction.showDialog({
      title: config.marker,
      message: config.content,
    });
    await this.checkPermissions();
    return true;
  }

  private async checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
    let atManager = abilityAccessCtrl.createAtManager();
    let grantStatus: abilityAccessCtrl.GrantStatus;

    try {
      const bundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
      const appInfo = bundleInfo.appInfo;
      const tokenId = appInfo.accessTokenId;
      grantStatus = await atManager.checkAccessToken(tokenId, permission);
    } catch (err) {
      console.error(`checkAccessToken failed, code: ${err.code}, message: ${err.message}`);
      grantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
    }
    return grantStatus;
  }

  private async checkPermissions(): Promise<void> {
    const permissions: Array<Permissions> = ['ohos.permission.READ_CALENDAR'];
    const grantStatus = await this.checkAccessToken(permissions[0]);

    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      console.debug('DialogManager', 'Permission granted');
    } else {
      console.debug('DialogManager', 'Permission denied, requesting permission');
    }
  }
}

デザインパターンの分析

元のコード

元のコードには3つの主要なコンポーネントが含まれています:AlertDialogConfigBuilder クラスはダイアログ設定を構築し、AlertDialogConfig クラスはダイアログ設定を保持します。

変更後のデザインパターン:

  1. ビルダー・パターン(Builder Pattern)

    • DialogConfigBuilder はビルダー・パターンを使用し、withPrimaryButton および withSecondaryButton メソッドで設定項目を設定し、build メソッドで設定オブジェクトを生成します。
    • 追加された buildAndShow メソッドにより、ダイアログの構築と表示を一度に行うことができ、ユーザーの呼び出しプロセスを簡略化します。
  2. シングルトン・パターン(Singleton Pattern)

    • DialogManager は静的な getInstance メソッドによって唯一のインスタンスを保証し、ダイアログの管理と表示を担当します。
  3. ファクトリ・メソッド・パターン(Factory Method Pattern)

    • 静的な create メソッドを通じて DialogConfigBuilder のインスタンスを作成し、オブジェクト作成プロセスをさらに簡略化します。

変更後の利点

  1. 呼び出しの簡便性

    • ユーザーは buildAndShow メソッドを一度呼び出すだけでダイアログを構築し表示できるため、コード量と呼び出しステップが削減され、ユーザーエクスペリエンスが向上します。
  2. 可読性と保守性の強化

    • withPrimaryButtonwithSecondaryButtonbuildAndShow などの明確で直感的な命名により、コードの可読性が大幅に向上し、オブジェクトの作成プロセスがより分かりやすくなります。
  3. コードの一貫性と拡張性の向上

    • buildAndShow メソッドの導入により、ユーザーは DialogManagershow メソッドを明示的に呼び出す必要がなくなり、コードの呼び出し一貫性が保たれます。新しい設定項目や機能を追加する際は、DialogConfigBuilder クラスのみを修正すれば十分です。

まとめ

再設計されたコードは、従来のデザインパターンを維持しつつ、コード構造と呼び出しフローをさらに最適化しています。変更後はユーザーの呼び出しがより簡単になり、重複操作が削減されるだけでなく、コードの可読性、保守性、拡張性も向上し、優れたソフトウェア設計とコーディング規範を示しています。

これらの改善により、開発プロセスが簡略化され、コードのレビューと最適化が容易になります。デザインパターンに対する深い理解と応用能力が反映されています。

タグ: ArkTS Dialog BuilderPattern SingletonPattern FactoryMethodPattern

5月28日 20:30 投稿