浜松のWEBシステム開発・スマートフォンアプリ開発・RTK-GNSS関連の開発はお任せください
株式会社シーポイントラボ
TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:静岡県浜松市中区富塚町1933-1 佐鳴湖パークタウンサウス2F

問題の細分化とソースコードの関数化

 よく関数にまとめることでソースコードが読みやすくなる、再利用しやすくなると言われますが、いきなりその様ことだけ知ってもすぐにできるものではありません。関数化の指針の一つに問題の細分化というものがあります。これは分割された小さな問題ごとに関数にしていくというやり方です。例えば次のコードがあります。

// 与えられた緯度経度に最も近い 'array' の要素を返す。
// 地球が完全な球体であることを前提としている。
var findClosestLocation = function (lat, lng, array) {
	var closest;
	var closest_dist = Number.MAX_VALUE;
	for (var i = 0; i < array.length; i += 1) {
		// 2 つの地点をラジアンに変換する。
		var lat_rad = radians(lat);
		var lng_rad = radians(lng);
		var lat2_rad = radians(array[i].latitude);
		var lng2_rad = radians(array[i].longitude);
		// 「球面三角法の第二余弦定理」の公式を使う。
		var dist = Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) +
				Math.cos(lat_rad) * Math.cos(lat2_rad) *
				Math.cos(lng2_rad - lng_rad));
		if (dist < closest_dist) {
			closest = array[i];
			closest_dist = dist;
		}
	}
	return closest;
};
Dustin Boswell; Trevor Foucher. リーダブルコード (Kindle の位置No.1930-1939). 株式会社オライリー・ジャパン. Kindle 版. 

 これはコードの最上部のコメントにあるように、与えられた緯度経度に最も近い 'array' の要素を返す、ことが最終目的の関数です。この目的を達成するためにこのコードは、2地点間の距離を算出する、最小の距離になる'array'の要素を発見する、という二つの問題を解いています。前者の2地点間の距離を算出する、という問題は最終目的から分割して考えられます。分割するという考えに沿ってコードを改造すると次の様になります。

// 与えられた緯度経度に最も近い 'array' の要素を返す。
// 地球が完全な球体であることを前提としている。
var findClosestLocation = function (lat, lng, array) {
	var closest;
	var closest_dist = Number.MAX_VALUE;
	var dist = spherical_distance(lat, lng, array[i].latitude, array[i].longitude);
	for (var i = 0; i < array.length; i += 1) {
		if (dist < closest_dist) {
			closest = array[i];
			closest_dist = dist;
		}
	}
	return closest;
};
function spherical_distance(lat, lng, lat_2, lng_2){
	//地点(lat,lng)と地点(lat_2,lng_2)の球面距離を返す
	// 2 つの地点をラジアンに変換する。
	var lat_rad = radians(lat);
	var lng_rad = radians(lng);
	var lat2_rad = radians(lat_2);
	var lng2_rad = radians(lng_2);
	// 「球面三角法の第二余弦定理」の公式を使う。
	return Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) +
		Math.cos(lat_rad) * Math.cos(lat2_rad) *
		Math.cos(lng2_rad - lng_rad));
}

 最初より簡単な関数であるfindClosestLocationとspherical_distanceの二つが出来ました。また、この関数化は再利用等のコードの変更を容易にします。例えば、findClosestLocation中のspherical_distance(lat, lng, array[i].latitude, array[i].longitude)という部分は呼び出す関数名の変更だけで同じような度単位の二地点の緯度経度を引数にする別の関数を用いることが出来ます。二地点間の球面距離の算出というのは多用します。
 問題の細分化の基準として意図と実装の乖離があります。あるコードを書いている時、そのコードに当初と別の目的が存在するならば、それは別の問題である、というものです。

  • この記事いいね! (0)