web-dev-qa-db-ja.com

If-lessプログラミング(基本的に条件なし)

私は同僚に、コードに条件(「if」および「switch」ステートメント)を含めないというポリシーとして働いていたことがあり、コードのすべての決定がポリモーフィズムと他のOO原則。

私は一種のより多くのDRYで更新しやすいコードを持つこと)の背後にある理由を理解していますが、私はこのコンセプトのより詳細な説明を探しています。または、より一般的な設計アプローチの一部です。

誰かがこれについてのリソースを持っているか、またはこれに関連するいくつかの用語を説明したり、喜んで持っているなら、もっと答えを見つけるために使用できます。

私は SOに関する1つの質問 を見つけましたが、これは関連性がありますが、C++に不慣れなので、あまり多くの答えを理解できません。

(私はOO guru btwですが、私は管理できます)

私はPHPに最も精通しており、その後Pythonなので、これらの言語を使用する情報を希望します。

更新:同僚に、彼が正確に何を意味しているかについての詳細な情報を求めます。

更新2015:プログラミングでの長年の経験の後、このポリシーの目的はおそらく、特定の場所に条件(ifステートメント)を追加するだけで、プログラマーが無計画な方法で機能を追加することを防ぐことであることがわかりました。ソフトウェアを拡張するより良い方法は、 "オープン/クローズドプリンシパル" を使用することです。ここでは、継承とポリモーフィズムを使用してソフトウェアを拡張します。ポリシーがないと完全に実行するのが少し難しいので、ポリシーがすべての条件に対して非常に厳しいかどうかを強く疑います。

64
Niels Bom

この記事 などの Anti-IFキャンペーン サイトにはいくつかのリソースがあります。

程度の問題だと思います。条件は必ずしも悪いわけではありませんが、悪用される可能性があります(そして頻繁に悪用されます)。

追加の考え(1日後)

リファクタリング:既存のコードの設計の改善 は、このテーマ(および他の多くのテーマ)の参考資料です。 ConditionalをPolymorphismに置き換える を対象としています。また、新しいもの ConditionalをVisitorに置き換える がWebサイトにあります。

すべてのifステートメントを削除するよりも単純さと 単一責任 を重視しています。これらの3つの目標はしばしば一致します。 循環的複雑度 メトリックをサポートする静的分析ツールは、ネストされた条件またはシリアル条件を持つコードをすばやく指摘できます。 ifステートメントはリファクタリング後も残る場合がありますが、より小さなメソッドや複数のクラスに分割できます。

更新:Michael Feathersは 無条件プログラミング に関する記事を書きました。

これは一般的なトピックです:Phil Haack on Death to the IF statement

54
TrueWill

プログラミングの数年後、私は自分の質問に戻りますが、そのコンテキストは今では少しよく理解できています。

Sandi Metzによる良い講演があります。彼女はif文の本当に毛むくじゃらのボールを、毛むくじゃらではない何かにリファクタリングします。 https://www.youtube.com/watch?v=8bZh5LMaSmE

12
Niels Bom

私はあなたがリンクした投稿を読みましたが、彼らは主に条件の必要性を取り除くことについて話していたようですクラス内、一般的にすべてのコードと混同しないでください。オブジェクトの状態をチェックして(条件を使用して)特定の機能があるかどうかを判断する必要がある場合、実際には2つのオブジェクト(機能をサポートするオブジェクトとサポートしないオブジェクト)があり、それらを2代わりに関連クラス。

7
user849425

私は同僚に、コードに条件(「if」および「switch」ステートメント)を含めないというポリシーとして働いていたことがあり、コードのすべての決定がポリモーフィズムと他のOO原則。

あなたの同僚は何かを誤解したか、間違った言葉を使って説明したと思います。また、条件文を完全に回避することはできません。

言いたいことがあります:OOPの中のifステートメントの増殖は、プログラミングの悪さの症状かもしれません。いくつかの例:

古いCスタイルのプログラミングのように、関数の戻り値をチェックする場合は使用しないでください。

int ret = some_func();
if (ret != null)
   //do something

これはCコードでは一般的でしたが、OOPでは例外を使用する必要があります。

try{
    do_something();
}catch(Exception e){
    e.printStackTrace(); //why I was not able to do something
    handle(e); //there is something else I could do to handle the occurred error
}

ステートメントの増殖が悪いデザインに関連している場合があります。 Javaでの次の例を検討してください。

BaseClass base;
if (base instanceof DerivedClassOneFromBase){
    DerivedClassOneFromBase d = (DerivedClassOneFromBase)base;
    d.methodOne();
}else if (base instanceof DerivedClassOneFromBase){
    DerivedClassTwoFromBase d = (DerivedClassTwoFromBase)base;
    d.methodTwo();
}

これは、不適切なifステートメントの別の例であり、おそらく不適切なデザインに関連しています。 2つの派生オブジェクトの基本クラスBaseClassで共通のメソッドが定義されている場合、具体的な型をチェックしてキャストする代わりに、そのメソッドを呼び出すことができます。

base.commonMethod();
7
Heisenbug

1つのメソッドで複数の関数または複数のタイプのメソッドを実行しているだけの兆候であるため、メソッド内の条件が悪い場合があります。

Automobileというクラスと、CarやBikeなどのサブクラス、および次のようなメソッドがある場合:

drive(Automobile a)
   if (a.isCar)
      // do stuff
   else if (a.isBike)
      // do stuff

あなたは何か間違ったことをしているようです。タイプに基づいたスイッチではない場合でも、しばしば間違っている可能性があります。メソッドがいくつかの変数に応じて複数の機能を実行している場合、多くの場合、複数のことを実行しようとしているため、おそらく複数のメソッドに分割する必要があります。

例えば:

save(Car c)
   if (c is new)
      // do some stuff
   else if (c is old)
      // do some stuff

これらは2つの異なる機能であるため、保存と更新に分割される可能性があります。それは依存しますが。

多くの有効なユースケースがあるため、ステートメントがばかげている場合は完全に禁止します。

4
BobTurbo

条件を回避することは、必ずしもポリモーフィズムまたは継承によって完了する必要があることを意味するわけではありません。たとえば、

アップロードされた画像、アップロードされた動画、アップロードされたPDFを保存するための3つの異なるフォルダーがあります

次のようにコードを書くことができます。

uploadMedia(mediaType){
   if(mediaType == images){
     uploadTo("myProject/images");
   }else if(mediaType == videos){
     upoloadTo("myProject/videos);  
   }else if(mediaType == pdf){
     uploadTo("myProject/pdf");
  }
}

人々が使用するかもしれない別の選択肢はswitch-caseです:

uploadMedia(mediaType){
         switch(mediaType){
         case : images
         uploadTo("myProject/images");
         break;

         case : videos
         uploadTo("myProject/videos");
         break;

         case : pdf
         uploadTo("myProject/pdf");
         break;
    }
}

ただし、辞書/ハッシュマップ/ jsonのようなものを使用することで、条件付きステートメントを完全に回避できます(作業内容によって異なります)。

例えば ​​:

HashMap<String,String> mediaMap = new HashMap<>();

mediaMap.put("images","myProject/images");
mediaMap.put("videos","myProject/videos");
mediaMap.put("pdf","myProject/pdf");

//mediaType can be images/videos/pdf same as keys of mediaMap
uploadMedia(mediaType){
  uploadTo(mediaMap.get(mediaType));
}

これは一種の擬似コードであるため、構文に誤りがある可能性がありますが、全体的にこの概念は条件を回避するのにも役立ちます。また、コードの行を減らすことができます。

0
TGW