控制结构(4): 局部化(localization)

// 上一篇:状态机(state machine)
// 下一篇:必经之地(using)


基于语言提供的基本控制结构,更好地组织和表达程序,需要良好的控制结构。

前情回顾

上一次,我们说到状态机结构(state machine),事实上,编程语言中有很多所谓的“高级”控制结构,内部都是状态机结构,差别只在于,这是编程语言内置提供的还是外置类库做。后面我们会有机会一点点展开它们,状态机的原理简洁,理解了它,再去理解那些高级控制结构的时候,才会觉的自然。再次回顾下状态机的原理:

  • define states
  • function dowork by switch states
  • in branch methods or events
    • check state
    • do real work
    • change state
    • reentry dowork function

下面我们看一种新的case。

典型代码

try-catch 情景

function loadPackage(packageName){
	try{
		let packageInfo = getPackageInfo(packageName);
	    let configPath = packageInfo.path + '/config.json';
	    let package = JSON.parse(fs.readFileSync(configPath));
	    return package;
   	}catch(err){
        return null;
    }
}

lock 情景

typedef std::map<K*,V*> Dict;
Dict dict;
Lock* lock = new Lock();

int Add(K* key, V* value){
	lock->lock();
	Dict::iterator it = dict.find(key);
	if (it == Dict.end()){
		key->AddRef();
		value->AddRef();
		dict.insert(std::make_pair(key, value));
	}
	lock->unlock();
	return RESULT.SUCCESS;	
}

int Remove(K* key){
	lock->lock();
	K* oldKey = NULL;
	V* oldValue = NULL;

	Dict::iterator it = dict.find(key);
	if (it != dict.end()){
		oldKey = it->first;
		oldValue = it->second;
		dict.erase(it);
	}

	if (oldKey){
		oldKey->Release();
	}

	if (oldValue){
		oldValue->Release();
	}

	lock->unlock();

	return RESULT.SUCCESS;
}

V* Find(K * key){
	lock->lock();

	K* oldKey = NULL;
	V* oldValue = NULL;

	dict::iterator it = dict.find(key);
	if (it != dict.end())
	{
		oldKey = it->first;
		oldValue = it->second;	
	}

	oldValue->AddRef();

	lock->unlock();
	return oldValue;
}

结构分析

上述两个示例代码,一个用到了try-catch,另一个用到了lock。例子里的代码不复杂,但是在编程中,也是一种常见的问题。那就是try-catch和lock的作用域是在一整段函数范围内都起作用。我们先缩小下范围:

try-catch 情景

function loadPackage(packageName){
	let packageInfo = getPackageInfo(packageName);
	let configPath = packageInfo.path + '/config.json';
       
    // catch scope
	try{
	    let package = JSON.parse(fs.readFileSync(configPath));
	    return package;
   	}catch(err){
        return null;
    }
}

lock 情景

typedef std::map<K*,V*> Dict;
Dict dict;
Lock* lock = new Lock();

int Add(K* key, V* value){
	lock->lock();
	Dict::iterator it = dict.find(key);
	if (it == Dict.end()){
		key->AddRef();
		value->AddRef();
		dict.insert(std::make_pair(key, value));
	}
	lock->unlock();
	return RESULT.SUCCESS;	
}

int Remove(K* key){
	K* oldKey = NULL;
	V* oldValue = NULL;

	// lock scope
	{
		lock->lock();
		Dict::iterator it = dict.find(key);
		if (it != dict.end()){
			oldKey = it->first;
			oldValue = it->second;
			dict.erase(it);
		}
		lock->unlock();
	}
	
	if (oldKey){
		oldKey->Release();
	}

	if (oldValue){
		oldValue->Release();
	}

	return RESULT.SUCCESS;
}

V* Find(K * key){
	K* oldKey = NULL;
	V* oldValue = NULL;
 
    // lock scope
	{
		lock->lock();
		dict::iterator it = dict.find(key);
		if (it != dict.end())
		{
			oldKey = it->first;
			oldValue = it->second;	
		}
		lock->unlock();
	}
		
	oldValue->AddRef();

	return oldValue;
}

语义分析

在上述两种情景下,关键是要区分出:“一个保护范围的作用目标是什么”。

try-catch只需要捕获文件读写和Json转换的异常,而不应该把其他代码包含进来。特别是getPackageInfo是一个函数调用,一个函数调用里面什么都可能发生,不应该被语义不明确地包含在此处的异常捕获里。

lock则要明确保护的是数据还是行为。此处lock应该保护的是dict容器在多线程里读写的互斥,所以不应该把除了对dict操作的其他逻辑包含进去。特别是oldKey->Release(), oldValue->Release()两个函数调用会有释放资源的行为,里面什么都可能发生,不应该被语义不正确地包含在此处的加锁范围内。

posted @ 2017-05-03 19:31  ffl  阅读(766)  评论(2编辑  收藏  举报