プログラミング/構造化プログラミング

構造化プログラミングとは

編集

構造化プログラミングは、プログラムを明確で理解しやすい制御構造に分解するプログラミングパラダイムです。この手法は、複雑なプログラムを、より単純で管理しやすい部分に分割することを目指します。

主要な原則

編集
  1. 順次実行
  2. 選択(条件分岐)
  3. 繰り返し(ループ)
  4. モジュール化
  5. 単一入口・単一出口

基本的な制御構造

編集

順次実行

編集
C言語
#include <stdio.h>

int main() {
    int x = 10;
    int y = 20;
    int sum = x + y;
    printf("合計: %d\n", sum);
    return 0;
}
Go
func calculateSum() int {
    x := 10
    y := 20
    sum := x + y
    return sum
}

条件分岐

編集
C++
int classifyNumber(int x) {
    if (x > 0) {
        return 1;  // 正の数
    } else if (x < 0) {
        return -1;  // 負の数
    } else {
        return 0;  // ゼロ
    }
}
Rust
fn classify_number(x: i32) -> i32 {
    match x {
        x if x > 0 => 1,
        x if x < 0 => -1,
        _ => 0
    }
}

繰り返し構造

編集
Java
public class LoopExamples {
    // 単純なforループ
    public void printNumbers() {
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
        }
    }
    
    // whileループ
    public int sumUpTo(int limit) {
        int sum = 0;
        int counter = 1;
        
        while (counter <= limit) {
            sum += counter;
            counter++;
        }
        
        return sum;
    }
}
C#
public class LoopExamples {
    // forとforeachの比較
    public void IterateCollection() {
        int[] numbers = { 1, 2, 3, 4, 5 };
        
        // 伝統的なforループ
        for (int i = 0; i < numbers.Length; i++) {
            Console.WriteLine(numbers[i]);
        }
        
        // foreachループ
        foreach (int num in numbers) {
            Console.WriteLine(num);
        }
    }
}

モジュール化と関数分解

編集

関数による問題分解

編集
Go
func calculateTax(income float64) float64 {
    return calculateBasicTax(income) + calculateAdditionalTax(income)
}

func calculateBasicTax(income float64) float64 {
    if income <= 50000 {
        return income * 0.1
    }
    return 5000 + (income - 50000) * 0.2
}

func calculateAdditionalTax(income float64) float64 {
    if income > 100000 {
        return (income - 100000) * 0.3
    }
    return 0
}

再帰と反復

編集
Rust
// 反復的なアプローチ
fn factorial_iterative(n: u64) -> u64 {
    let mut result = 1;
    for i in 1..=n {
        result *= i;
    }
    result
}

// 再帰的なアプローチ
fn factorial_recursive(n: u64) -> u64 {
    if n == 0 || n == 1 {
        1
    } else {
        n * factorial_recursive(n - 1)
    }
}

エラーハンドリングと防御的プログラミング

編集

エラー処理のパターン

編集
C++
#include <stdexcept>

class DivisionHandler {
public:
    static double safeDivide(double numerator, double denominator) {
        if (denominator == 0) {
            throw std::invalid_argument("ゼロによる除算は許可されていません");
        }
        return numerator / denominator;
    }
};

デザインパターンと構造化プログラミング

編集

単一責任原則の実践

編集
Java
// データ処理クラス
class DataProcessor {
    public List<Integer> filterEvenNumbers(List<Integer> numbers) {
        return numbers.stream()
                      .filter(n -> n % 2 == 0)
                      .collect(Collectors.toList());
    }
}

// データ表示クラス
class DataPresenter {
    public void printNumbers(List<Integer> numbers) {
        numbers.forEach(System.out::println);
    }
}

構造化プログラミングの利点

編集
  1. コードの可読性向上
  2. デバッグの容易さ
  3. 保守性の改善
  4. 論理的な問題解決アプローチ

注意点と発展

編集
  • 過度な関数分割は複雑さを増す可能性がある
  • コンテキストに応じた柔軟な設計が重要
  • 他のパラダイム(関数型、オブジェクト指向)との組み合わせ

まとめ

編集

構造化プログラミングは、体系的で論理的なプログラム設計の基礎を提供します。制御構造を明確に理解し、問題を小さな、管理可能な部分に分解することで、より堅牢で理解しやすいコードを作成できます。

推奨される学習ステップ

編集
  1. 基本的な制御構造の完全な理解
  2. 関数による問題分解の実践
  3. エラーハンドリングの技術
  4. デザインパターンと原則の学習
  5. 異なる言語での実装比較