1

重複の可能性:
関数/プロシージャ/メソッドには何行のコードが必要ですか?

Outチームには、適切に構造化されていないansi-cコードのプロジェクトがあります。いくつかのCC手法を使用して、コードベースを整理したいと思います。

Cコードに関しては、多くのポインターと、キャッチすべきNULLポインターの落とし穴がたくさんあります。したがって、似ているフラグメントがたくさんあります。まるで

if (pointer == NULL)
{
  function1();
  function2();
}

あらゆる所に。次に、いくつかのバリエーションだけで同じ方法で次々に呼び出される関数が非常にたくさんあります。

function1();
function2a();
function3();

function1();
function2b();
function3();

あらゆる所に。

LOCとコピー貼り付けを減らすために、これらのブロックを単一の関数として抽出したいと思います。しかし、それは(ある程度)直交するレイヤーを作成するだけでなく、いくつかの詳細を除いて、多かれ少なかれ同じことを行う一握りの機能も作成します。さらに悪いことに、それは一度に多くのことを行う関数を作成します。

それで、良い戦略は何ですか?より重要なのは、高レベルのリーンコード、低レベルのリーン関数、またはリーンアーキテクチャですか?どちらの原則が他の原則に勝っていますか?懸念の分離またはDRY?

その獣をリファクタリングしたいのですが、どこから始めればよいのかわかりません。

以下の例を説明し、同じ名前を入れます。

morningBath();
drinkCoffee();
if (checkMail())
{
  answerMail();
}

そしてそれをmorningRoutine()に入れます。今、私たちは持っています

drinkTea();
morningBath();
if (checkMail())
{
  answerMail();
}

そしてそれをsundayMorningRoutine()と呼びます。しかし、重複したコードがあります。または、morningRoutine(day)を次のように展開します

if (day == sunday){
  drinkTea();
  morningBath();
} else {
  morningBath();
  drinkCoffee();
}    
if (checkMail())
{
  answerMail();
}

または多分

if (day == sunday){
  drink(Tea);
  morningBath();
} else {
  morningBath();
  drink(Coffee);
}    
if (checkMail())
{
  answerMail();
}

それは良いスタイルかしら..多分..そのヒントをありがとう!

4

3 に答える 3

1

Philip の言ったことには大いに同意しますが、Clean Code の主なポイントの 1 つは、コードを英語のように読めるようにすることだと付け加えたいと思います。関数の一般的なシーケンスに遭遇し、そのシーケンスに適切な名前を付けることができない場合は、そのままにしておくことをお勧めします。たとえば、

vacuumTheCarpet();
dustTheFurniture();
putThingsInTherePlace();

これを次のように置き換えることができます

cleanTheHouse();

しかし、もしあなたが持っているなら

getTheMail();
eatSomeIceCream();
writeALetter();

おそらく、それらを別々の関数として残しておく方がよいでしょう。

于 2012-07-27T12:39:59.913 に答える
1

エラー チェックの場合、マクロを使用するとコードがよりきれいになります。

#define CheckNullLogClean(ptr) if(ptr == NULL) { \
    status = ERR_NULL_PTR; \
    LogError(status); \
    goto cleanup; }

int func(int *input) {
    status = 0;
    CheckNullLogClean(input);
    Do_Things();
    cleanup:
    Release_Resources();
    return status;
}

私が取り組んでいたコードベースは、これと同様のことを行いました。statusまた、すべての関数は、 というラベルの後に (モジュール スコープのエラー コード テーブルの値を含む)という整数を返すように設定されていましたcleanup。各関数呼び出しがその戻り値をチェックした場合、ログ ファイルには、ファイル名と行番号を含むスタック トレースが含まれます (はおよびマクロを使用LogErrorして関数を呼び出すマクロでした)。また、プロジェクト全体で同じエラー チェック マクロを使用できます。__FILE____LINE__

ああ、もしあなたの関数が同様の目的を果たしているなら、おそらく関数ポインタ配列を反復処理するのが理にかなっているでしょう。

于 2012-07-27T13:39:41.077 に答える
1

C コードに関してNULLは、特に関数の引数に関しては、ポインター チェックが頻繁に発生するのはまったく普通のことです。個人的には、次のように発信者に状況を解決してもらうことを好みます。

if (p == NULL) {
    /* maybe do some cleanup and then: */
    return errcode;
}

パブリック関数、つまり API の一部である関数は、常にNULLポインターをチェックする必要があります。指定された関数は、staticIMO がそれらのチェックをドロップする場合があります。最後に、常にありassert()ます。これらのチェックは、コンパイラ フラグによって抑制できます-NDEBUG。-statementsの代わりに関数内で使用assert()し、呼び出し元が API 全体を実際に理解していないことを明らかにするテスト用の「パブリック」関数内 (リンクされたリスト lib など) を使用します。staticif

void list_print(list **l)
{
    assert(l != NULL);    /* no valid list passed by reference can ever be NULL */

    if (*l == NULL)       /* but it can be empty */
        return;

    /* print list */
}


2 番目の懸念については、次の 3 つの選択肢があります。

1)すべてをそのままにしておきます-結局、それは機能しています。

2) 新機能の導入:

int function_1_2a_3();
int function_1_2b_3();

3) 新しいパラメーター化された関数を導入します。

int function_1_2_3(int type);

個人的には後者のアプローチを好みますが、それはスタイルの問題です。

于 2012-07-27T12:28:08.907 に答える