一般に、デザインパターンはOOプログラミングに関連するものですが、Cをプログラミングするときによく使用するパターンはありますか?
私は古典的なOOパターンの単純な翻訳には興味がありません。ダフのデバイスについては言及しないでください。;-)
私のお気に入りは Adam Petersen による "Cのパターン"シリーズです。
また、私はgoto
をデコレータパターン用の非常に貧しい人のツールと常に考えています。
Update:Rust( cを使用する必要がある場合を除き、CではなくRust-lang.org )。 Rustは、cとの速度やバイナリライブラリの互換性など、cのすべての利点を備えていますが、コンパイラは、コードがメモリセーフでデータ競合を含まないことを保証するために複雑さの多くを処理します。また、移植性があり、一般的なタスク用の標準ライブラリを備えており、さまざまなデザインパターンでのプログラミングがはるかに簡単です。
デザインパターンは、言語機能が欠落していると見なされる可能性があります。 設計パターン:再利用可能なオブジェクト指向ソフトウェアの要素 の紹介:
プログラミング言語の選択は、自分の視点に影響を与えるため重要です。私たちのパターンは、Smalltalk/C++レベルの言語機能を想定しており、その選択によって簡単に実装できるものとできないものが決まります。 手続き型言語を想定した場合、「継承」、「カプセル化」、および「ポリモーフィズム」と呼ばれる設計パターンが含まれている可能性があります。同様に、パターンの一部あまり一般的ではないオブジェクト指向言語によって直接サポートされています。たとえば、CLOSには複数のメソッドがあり、Visitorなどのパターンの必要性を減らします。 (イタリック鉱山)
斜体の文は、あなたの質問に対する答えです。
はい、あります。遅延初期化、シングルトン、オブジェクトプール、オブジェクト状態などは、純粋なCで簡単に実装できます。
例(遅延初期化)
#include <stdio.h>
struct foo
{
int payload;
};
int calculate_payload()
{
printf("%s\n", "Performing lengthy initialization...");
return 42;
}
struct foo *get_default_foo()
{
static int foo_calculated = 0;
static struct foo default_foo;
if (!foo_calculated) /* assuming single-threaded access */
{
foo_calculated = 1;
default_foo.payload = calculate_payload();
}
return &default_foo;
}
int main()
{
struct foo *foo1, *foo2;
printf("%s\n", "Starting the program");
foo1 = get_default_foo();
printf("%d\n", foo1->payload);
foo2 = get_default_foo();
printf("%d\n", foo2->payload);
return 0;
}
コールバックを介したポリモーフィズム、例えば標準ライブラリのqsort
関数。必要なのは、2つの要素を比較する方法だけで、それらの配列をソートできます。
関数(vtables)のセットを使用して型の適切なプロパティを表すことにより、汎用ルーチンで便利に処理できるようにすることで、これよりもはるかに高度なものにすることができます。たとえば、読み取り、書き込みなどは、開いているファイルまたはネットワークポートを呼び出します。
多くの場合、デザインパターンは、既存の環境が提供するものから1レベルだけのものをモデル化します。環境としてCを標準ライブラリとともに使用する場合、顕著な設計パターンはオブジェクト指向です。
仮想ファイルシステムは、デザインパターンを学習するための完璧な例です。