vscode里面的常见设计模式

这篇具有很好参考价值的文章主要介绍了vscode里面的常见设计模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

vscode里面最常见的就是命令模式,无论是菜单还是按钮的点击事件大多都是以命令形式去执行的,这样的设计模式在代码的可读上更清晰明了。

在早我写过一篇有关js几种常见设计模式的demo,感兴趣的看我这篇文章:https://blog.csdn.net/woyebuzhidao321/article/details/120235389。

命令模式

我们看下vscode里面最简单的命令注册
src/vs/workbench/contrib/files/browser/fileActions.ts

CommandsRegistry.registerCommand({
	id: NEW_FILE_COMMAND_ID,
	handler: async (accessor) => {
		await openExplorerAndCreate(accessor, false);
	}
});

这里的id是唯一的,handler是对应的执行函数。
我们跳入registerCommand方法里面。

export const CommandsRegistry: ICommandRegistry = new class implements ICommandRegistry {

	private readonly _commands = new Map<string, LinkedList<ICommand>>();

	private readonly _onDidRegisterCommand = new Emitter<string>();
	readonly onDidRegisterCommand: Event<string> = this._onDidRegisterCommand.event;

	registerCommand(idOrCommand: string | ICommand, handler?: ICommandHandler): IDisposable {

		if (!idOrCommand) {
			throw new Error(`invalid command`);
		}

		if (typeof idOrCommand === 'string') {
			if (!handler) {
				throw new Error(`invalid command`);
			}
			return this.registerCommand({ id: idOrCommand, handler });
		}

		// add argument validation if rich command metadata is provided
		if (idOrCommand.description) {
			const constraints: Array<TypeConstraint | undefined> = [];
			for (let arg of idOrCommand.description.args) {
				constraints.push(arg.constraint);
			}
			const actualHandler = idOrCommand.handler;
			idOrCommand.handler = function (accessor, ...args: any[]) {
				validateConstraints(args, constraints);
				return actualHandler(accessor, ...args);
			};
		}

		// find a place to store the command
		const { id } = idOrCommand;

		let commands = this._commands.get(id);
		if (!commands) {
		   // 以健值对形式存储到map对象里统一管理
			commands = new LinkedList<ICommand>();
			this._commands.set(id, commands);
		}

		let removeFn = commands.unshift(idOrCommand);

		let ret = toDisposable(() => {
			removeFn();
			const command = this._commands.get(id);
			if (command?.isEmpty()) {
				this._commands.delete(id);
			}
		});

		// tell the world about this command
		this._onDidRegisterCommand.fire(id);

		return ret;
	}
...
}

可以看到以健值对形式存储到_commands map对象里统一管理起来。id作为key,value是链表数据结构

接下来我们看看是如何通过按钮去调用的
src/vs/workbench/contrib/files/browser/views/explorerView.ts

registerAction2(class extends Action2 {
	constructor() {
		super({
			id: 'workbench.files.action.createFileFromExplorer',
			title: nls.localize('createNewFile', "New File"),
			f1: false,
			icon: Codicon.newFile,
			precondition: ExplorerResourceNotReadonlyContext,
			menu: {
				id: MenuId.ViewTitle,
				group: 'navigation',
				when: ContextKeyExpr.equals('view', VIEW_ID),
				order: 10
			}
		});
	}

	run(accessor: ServicesAccessor): void {
		const commandService = accessor.get(ICommandService);
		commandService.executeCommand(NEW_FILE_COMMAND_ID);
	}
});

可以看到通过执行 executeCommand方法去调用,我们看看executeCommand方法里面实现了什么

src/vs/workbench/services/commands/common/commandService.ts

async executeCommand<T>(id: string, ...args: any[]): Promise<T> {
		...
				return this._tryExecuteCommand(id, args);
			....	
	}
private _tryExecuteCommand(id: string, args: any[]): Promise<any> {
// 获取链表节点
		const command = CommandsRegistry.getCommand(id);
		if (!command) {
			return Promise.reject(new Error(`command '${id}' not found`));
		}
		try {
			this._onWillExecuteCommand.fire({ commandId: id, args });
			// 这里调用handler方法
			const result = this._instantiationService.invokeFunction(command.handler, ...args);
			this._onDidExecuteCommand.fire({ commandId: id, args });
			return Promise.resolve(result);
		} catch (err) {
			return Promise.reject(err);
		}
	}

可以看到通过getCommand方法通过id获取到了链表的节点,我们看下invokeFunction函数实现

src/vs/platform/instantiation/common/instantiationService.ts

invokeFunction<R, TS extends any[] = []>(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R {
		let _trace = Trace.traceInvocation(fn);
		let _done = false;
		try {
			const accessor: ServicesAccessor = {
				get: <T>(id: ServiceIdentifier<T>) => {

					if (_done) {
						throw illegalState('service accessor is only valid during the invocation of its target method');
					}

					const result = this._getOrCreateServiceInstance(id, _trace);
					if (!result) {
						throw new Error(`[invokeFunction] unknown service '${id}'`);
					}
					return result;
				}
			};
			return fn(accessor, ...args);
		} finally {
			_done = true;
			_trace.stop();
		}
	}

可以看到其实它就是调用了handler方法。这样从注册到执行的过程就通了。

发布订阅模式

在类里面定义事件

static readonly _onHandleChangeSearchDetail = new Emitter<boolean>();
static onHandleChangeSearchDetail: Event<boolean> = SidebarPart._onHandleChangeSearchDetail.event;

事件分发

SidebarPart._onHandleChangeSearchDetail.fire(true);

在其它类接收事件

// 调用Emitter类的event方法,传入一个回调函数,fire时触发
this._register(SidebarPart.onHandleChangeSearchDetail(flag => {
    console.log(333, flag);
}));

src/vs/base/common/event.ts文章来源地址https://www.toymoban.com/news/detail-528927.html

export class Emitter<T> {
	private readonly _options?: EmitterOptions;
	private readonly _leakageMon?: LeakageMonitor;
	private readonly _perfMon?: EventProfiling;
	private _disposed: boolean = false;
	private _event?: Event<T>;
	private _deliveryQueue?: LinkedList<[Listener<T>, T]>;
	protected _listeners?: LinkedList<Listener<T>>;

	constructor(options?: EmitterOptions) {
		this._options = options;
		this._leakageMon = _globalLeakWarningThreshold > 0 ? new LeakageMonitor(this._options && this._options.leakWarningThreshold) : undefined;
		this._perfMon = this._options?._profName ? new EventProfiling(this._options._profName) : undefined;
	}

...

	/**
	 * For the public to allow to subscribe
	 * to events from this Emitter
	 */
	 // 取.event的时候,执行的就是这里,它其实返回了一个方法:
	get event(): Event<T> {
		if (!this._event) {
			this._event = (callback: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {
				if (!this._listeners) {
					this._listeners = new LinkedList();
				}

				const firstListener = this._listeners.isEmpty();

				if (firstListener && this._options?.onFirstListenerAdd) {
					this._options.onFirstListenerAdd(this);
				}

				let removeMonitor: Function | undefined;
				let stack: Stacktrace | undefined;
				if (this._leakageMon && this._listeners.size >= 30) {
					// check and record this emitter for potential leakage
					stack = Stacktrace.create();
					removeMonitor = this._leakageMon.check(stack, this._listeners.size + 1);
				}

				if (_enableDisposeWithListenerWarning) {
					stack = stack ?? Stacktrace.create();
				}

				const listener = new Listener(callback, thisArgs, stack);
				const removeListener = this._listeners.push(listener);

				if (firstListener && this._options?.onFirstListenerDidAdd) {
					this._options.onFirstListenerDidAdd(this);
				}

				if (this._options?.onListenerDidAdd) {
					this._options.onListenerDidAdd(this, callback, thisArgs);
				}

				const result = listener.subscription.set(() => {
					if (removeMonitor) {
						removeMonitor();
					}
					if (!this._disposed) {
						removeListener();
						if (this._options && this._options.onLastListenerRemove) {
							const hasListeners = (this._listeners && !this._listeners.isEmpty());
							if (!hasListeners) {
								this._options.onLastListenerRemove(this);
							}
						}
					}
				});

				if (disposables instanceof DisposableStore) {
					disposables.add(result);
				} else if (Array.isArray(disposables)) {
					disposables.push(result);
				}

				return result;
			};
		}
		return this._event;
	}

	/**
	 * To be kept private to fire an event to
	 * subscribers
	 */
	 // 循环派发了所有注册的事件
	fire(event: T): void {
		if (this._listeners) {
			// put all [listener,event]-pairs into delivery queue
			// then emit all event. an inner/nested event might be
			// the driver of this

			if (!this._deliveryQueue) {
				this._deliveryQueue = new LinkedList();
			}

			for (let listener of this._listeners) {
				this._deliveryQueue.push([listener, event]);
			}

			// start/stop performance insight collection
			this._perfMon?.start(this._deliveryQueue.size);

			while (this._deliveryQueue.size > 0) {
				const [listener, event] = this._deliveryQueue.shift()!;
				try {
					listener.invoke(event);
				} catch (e) {
					onUnexpectedError(e);
				}
			}

			this._perfMon?.stop();
		}
	}

	hasListeners(): boolean {
		if (!this._listeners) {
			return false;
		}
		return (!this._listeners.isEmpty());
	}
}

到了这里,关于vscode里面的常见设计模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 常见设计模式

    单例模式 单例对象的类必须保证只有一个实例存在,整个系统只能使用一个对象实例,优点:不会频繁地创建和销毁对象,浪费系统资源。缺点是没有抽象层,难以扩展。 单例模式的常见写法: 饿汉式单例模式的写法:线程安全 ,顾名思义,类⼀加载就创建对象,这种⽅式

    2024年02月07日
    浏览(54)
  • 常见的设计模式(模板与方法,观察者模式,策略模式)

    随着时间的推移,软件代码越来越庞大,随着而来的就是如何维护日趋庞大的软件系统。在面向对象开发出现之前,使用的是面向过程开发来设计大型的软件程序,面向过程开发将软件分成一个个单独的模块,模块之间使用函数进行组合,最后完成系统的开发,每次需要修改

    2024年01月22日
    浏览(35)
  • 【了解一下常见的设计模式】

    **设计模式(Design Pattern)**是软件开发过程中一般问题的解决方案,是无数面向对象软件开发人员的经验总结,对于软件设计开发十分重要。然而由于设计模式种类繁多,内容偏理论,缺乏开发经验对于相关概念的理解也比较困难,同时其中不乏很多类型相似的设计模式,更

    2024年02月12日
    浏览(31)
  • 前端中常见的设计模式

    1.单例模式 描述:保证一个类仅有实例,并提供一个可以全局访问他的点,它通常用于管理应用程序的全局状态或资源,例如一个唯一的状态管理器。 代码示例: 2. 观察者模式 描述:观察者模式用于建立对象之间的一对多依赖关系,使得当一个对象的状态发生变化时,所有

    2024年02月13日
    浏览(32)
  • 常见的23种设计模式

    常见的设计模式有23种,它们分别是: 1. 工厂方法模式(Factory Method Pattern) 2. 抽象工厂模式(Abstract Factory Pattern) 3. 单例模式(Singleton Pattern) 4. 建造者模式(Builder Pattern) 5. 原型模式(Prototype Pattern) 6. 适配器模式(Adapter Pattern) 7. 桥接模式(Bridge Pattern) 8. 过滤器模

    2024年02月07日
    浏览(38)
  • 常见的设计模式(超详细)

    确保一个类只有一个实例,并且自行实例化并向整个系统提供这个实例。 饿汉式单例模式在类加载的时候完成了实例化,因为我们将构造函数设为了私有,所有其他的对象不能通过new类创建这个类的实例,然后提供了一个公共的静态方法返回这个类的唯一实例。因为只有一个

    2024年02月14日
    浏览(35)
  • 常见的五种设计模式

    https://www.runoob.com/design-pattern/factory-pattern.html **意图:**保证一个类仅有一个实例,并提供一个访问它的全局访问点。 **主要解决:**一个全局使用的类频繁地创建与销毁。 **何时使用:**当您想控制实例数目,节省系统资源的时候。 **如何解决:**判断系统是否已经有这个单例

    2024年02月07日
    浏览(43)
  • Unity中常见的设计模式

            设计模式是一系列被广泛使用且具有相似解决方案的问题或问题实例的解决方法。它们是软件设计领域中的通用解决方案,可以帮助开发人员轻松地解决常见的软件设计问题。对于Unity开发者来说,熟悉并掌握常用的设计模式可以帮助我们更好地组织和管理代码,

    2024年02月09日
    浏览(49)
  • PHP 常见设计模式及示例

    单例模式顾名思义,就是只有一个实例。作为对象的创建模式, 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 单例模式的要点有三个: 一是某个类只能有一个实例; 二是它必须自行创建这个实例; 三是它必须自行向整个系统提供这个

    2024年01月25日
    浏览(32)
  • Spring中常见的设计模式

    使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性、更具有灵活、优雅,而Spring中共有九种常见的设计模式 工厂模式 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创

    2024年02月20日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包