无处不在的耦合

通常你写的一个React组件,如果需要和别的组件发生交互,那么你会怎么做?

1
public componentDidMount(): void {
	this.refs.mycom.test();
}

public render() {
	return (
		<MyCom ref="mycom" />
	);
}

这种做法相对来说比较普遍,也比较合情合理,那么如果MyCom组件执行了什么操作之后需要通知到父组件呢?

1
public onNotify(): void {

}

public render() {
	return (
		<MyCom notify={ this.onNotify.bind( this ) } ref="mycom" />
	);
}

很多时候我们会选择传进去一个回调函数,当MyCom需要发送通知的时候再调用props.notify

虽然这种方式能实现我们的需求,但也仅仅是实现而已,你会发现这种方式并不是很优雅,而且当你的回调函数多了之后,那简直就是噩梦,后来来使用这个组件的人完全不知道需要传哪些回调函数进去,也不知道哪些回调是可选的,哪些是必选的。

protocol

ProtocolOc里面的概念,类似Java里面的Interface,和TypeScript中的Interface也比较类似,其中有一个用处就是用于两个类之间的通信解耦,而delegate更多的是一种约定俗成的规则,看看具体怎么用:

首先我有一个A类,用

A.h

1
@protocol ADelegate
	- (void) methodFromA;
@end

@interface A : NSObject
// 声明委托变量
@property (assign, nonatomic) id<ADelegate> delegate;
    - (void) test;
@end

A.m

1

// 在A类的实现文件里面,在需要进行回调的时候,只需要调用当前实例的delegate对象,而不用理会到底是谁调用了自己,而且对方肯定实现了delegate指向的protocol
// 需要的时候调用
[self.delegate methodFromA];

此时,我有一个B类,需要调用A类,同时需要监听回调函数:

B.h

1
#import "A.h"

// 这里实现了Adelegate Protocol
@interface B : NSObject <ADelegate>
...
@end

B.m

1
- (void) someMethod {
	A *aInstance = [[A alloc] init];
	// 这里把当前实例赋值给A类实例的delegate属性
	aInstance.delegate = self;	
}

// 实现了ADelegate
- (void) methodFromA {
	当A类调用self.delegate.methodFromA时,就可以在这里执行你自己的代码了
	// ...
}

TypeScript中的delegate

上面可以看到其实delegate的使用非常简单,只是一种约定的规则,同时delegate其实也是一种设计模式,在JS中其实也可以使用,只是JS是弱类型语言,无法通过编译器来约束一些行为,所以依赖于TypeScript的强类型,我们也可以来使用一下delegate

组件A

1
export interface ADelegate {
	methodFromA();
}

export class A extends React.Component<any, any> {
	public delegate: ADelegate;

	public render() {

		// 调用delegate的方法
		this.delegate.methodFromA();

		return (
			<div></div>
		);

	}

}

组件B

1
import { A, ADelegate } from 'A';

// 这里实现了Interface: ADelegate
export class B extends React.Component<any, any> implements ADelegate {
	// 从A实现的回调。
	public methodFromA(): void {

	}

	public componentDidMount(): void {
		const aCom: A = <A>this.refs.acom;
		aCom.delegate = this;
	}

	public render() {
		return (
			<A ref="acom" />
		);
	}
}

效果

上面的代码可以看到,A组件面向的不是调用他的组件,而是他自己声明的delegate,完全无需关心是谁在调用自己,在什么场景下调用自己

而B组件也完全不用关心A组件的具体实现,只要实现A组件提供的Interface:ADelegate,从中选择自己需要的方法即可,两者实现解耦,面向delegate编程。