1 简介

“Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.”

**

  • Class不可以被修改,但可以被继承,添加新的属性和方法来扩展功能_ ```typescript abstract class FileWriter { write(content: string): number; }

// buffered for a large-size file class BufferedFileWriter extends FileWriter { write(content: string): number; write(buff: ArrayBuffer, off: number, len: number): number; skip(num: number): number; }

// able to rollback class RollbackFileWriter extends FileWriter { write(content: string): number; rollback(): boolean; }

  1. - Function接口不可以被修改,但可以添加扩展参数来扩展功能
  2. ```typescript
  3. // a.ts
  4. export interface Options {
  5. op1: string;
  6. op2: number;
  7. }
  8. export function format(num: number, options: Options): string {
  9. // ...
  10. }
  11. // b.ts
  12. import type { Options } from 'a.ts';
  13. import { format } from 'b.ts';
  14. export interface Options {
  15. op3: boolean;
  16. }
  17. export function format(num: number, options: Options): string {
  18. // ...
  19. }

2 Example

  1. // @yy/sl-tools
  2. const format = (value: number, platformName: platformNameTypes): string | null => {
  3. const supportPlatforms = ['STOREFRONT', 'ADMIN', 'DASH'];
  4. const hitPlatform = supportPlatforms.indexOf(platformName) === -1;
  5. let baseFormatOptions;
  6. if (window === undefined) {
  7. return null;
  8. }
  9. if (hitPlatform) {
  10. console.error('请传入第二个参数platformName,目前仅支持STOREFRONT、ADMIN、DASH');
  11. return null;
  12. }
  13. if (platformName === 'STOREFRONT') {
  14. baseFormatOptions = {
  15. code: Cookies.get('currency_code'),
  16. lang: Cookies.get('lang'), // 目前商家前台还没有该字段.. todo...
  17. };
  18. } else if (platformName === 'ADMIN') {
  19. baseFormatOptions = {
  20. code: Cookies.get('a_currency_code'),
  21. lang: Cookies.get('a_lang'),
  22. };
  23. } else if (platformName === 'DASH') {
  24. baseFormatOptions = {
  25. code: Cookies.get('d_currency_code'), // 目前dash还没有该字段(预留)
  26. lang: Cookies.get('d_lang'), // 目前dash还没有该字段(预留
  27. };
  28. }
  29. return baseFormat(value, baseFormatOptions);
  30. };
  • 改变接口,不兼容旧版本:破坏client调用代码
    • 无法估计有多少Client
    • 海量回归测试
  • 耦合其他应用代码:貌离神合,仅仅是空间上的隔离
    • 应用修改影响公共包
    • 公共包修改影响应用
  • 耦合其他职责(读取Cookies):违反SRP原则
    • 分离配置读取代码
    • 约定接口或协议,而不约定实现


3 改进

  • configManager.ts ```typescript export enum StorageType { Cookies = ‘cookies’, SessionStorage = ‘sessionStorage’, LocalStorage = ‘localStorage’, IndexedDB = ‘indexedDB’, }

interface BaseOptions { type: StorageType; }

export interface Config { lang: string; code: string; }

interface CookiesOptions extends BaseOptions { key: Record; }

interface SessionStorageOptions extends BaseOptions { // … }

type LocalStorageOptions = interace SessionStorageOptions;

interface IndexedDBOptions extends BaseOptions { // … }

export type ConfigOptions = CookiesOptions | SessionStorageOptions | LocalStorageOptions | IndexedDBOptions;

export function getConfig(options: ConfigOptions): Config { // …. }

  1. - `currency.ts`
  2. ```typescript
  3. import _ from 'lodash';
  4. import type { CookiesOptions } from './configManager';
  5. import { StorageType, getConfig } from './configManager'
  6. let DEFAULT_OPTIONS: ConfigOptions = {
  7. type: StorageType.Cookies,
  8. key: {
  9. lang: 'lang',
  10. code: 'currency_code',
  11. },
  12. };
  13. let options: ConfigOptions = DEFAULT_OPTIONS;
  14. export function setOptions(opts: ConfigOptions) {
  15. // merge
  16. options = _.merge({}, DEFAULT_OPTIONS, opts);
  17. }
  18. export function formatCurrency(number) {
  19. // ...
  20. const config = getConfig(options);
  21. // ....
  22. }
  • 使用 ```typescript // 应用Admin初始化: app.ts

import { setOptions, StorageType } from ‘@yy/sl-tools’;

setOptions({ type: StorageType.Cookies, key: { lang: ‘a_lang’, code: ‘a_currency_code’ }, });

// 使用 import { formatCurrency } from ‘@yy/sl-tools’; formatCurrency(number); ```