DRYの原則を使用してロジックをリファクタリングする

マニル

C ++でプログラミングしているときに、次のようなソースコードに出くわしました。

int enemy = 1; //enemy can be 1 or -1
if (enemy == 1) {
    for (short i = 1; i < 100; i++) {
        if (some_array[i] <= enemy) {
            cout << i << ", ";
            do_sth(i);
        }
    }
} else if (enemy == -1) {
    for (short i = 1; i < 100; i++) {
        if (some_array[i] >= enemy) {
            cout << i << ", ";
            do_sth_else_here(i);
        }
    }
}

間違いなく、コードは本来あるべきことを実行しますが、DRYに反対し、厄介でもあります。

そこまでの方法である短縮コードは(例えばスワップときよりも小さいより大きいenemyですマイナス)またはより良いDRY原則に合うように、それをリファクタリング?

リチャードホッジス

読みやすさをあまり損なうことなく、関数を次のようなものに合理的に減らすことができると思います。

最初の試み

void handle_enemy(int enemy)
{
    assert(enemy == -1 or enemy == 1);
    if (enemy == 1) {
        check_enemy(enemy, std::less_equal<>(), &do_sth);
    } else if (enemy == -1) {
        check_enemy(enemy, std::greater_equal<>(), &do_sth_else_here);
    }
}

check_enemyリファクタリングされた場所

template<class Comparer, class Action>
void check_enemy(int enemy, Comparer comp, Action action)
{
    for (short i = 1; i < some_array.size(); i++) {
        if (comp(some_array[i], enemy))
        {
            std::cout << i;
            action(i);
            std::cout << ", ";
        }
    }
    std::cout << std::endl;
}

完全な実例:

#include <iostream>
#include <array>
#include <random>
#include <algorithm>
#include <cassert>

void do_sth(int i) { std::cout << '!' ; }
void do_sth_else_here(int i) { std::cout << '?'; }

std::array<int, 100> some_array;

template<class Comparer, class Action>
void check_enemy(int enemy, Comparer comp, Action action)
{
    for (short i = 1; i < some_array.size(); i++) {
        if (comp(some_array[i], enemy))
        {
            std::cout << i;
            action(i);
            std::cout << ", ";
        }
    }
    std::cout << std::endl;
}

void handle_enemy(int enemy)
{
    assert(enemy == -1 or enemy == 1);
    if (enemy == 1) {
        check_enemy(enemy, std::less_equal<>(), &do_sth);
    } else if (enemy == -1) {
        check_enemy(enemy, std::greater_equal<>(), &do_sth_else_here);
    }
}

int main()
{
    std::default_random_engine eng(std::random_device{}());
    std::generate(std::begin(some_array),
                  std::end(some_array),
                  [&eng,
                   dist = std::uniform_int_distribution<int>(-5, +5)]() mutable -> int
    {
        return dist(eng);
    });
    handle_enemy(-1);
    handle_enemy(1);

    return 0;
}

出力例:

1?, 3?, 4?, 5?, 6?, 7?, 10?, 11?, 13?, 15?, 16?, 17?, 18?, 21?, 22?, 23?, 24?, 25?, 26?, 27?, 28?, 30?, 32?, 33?, 34?, 35?, 39?, 40?, 42?, 43?, 45?, 46?, 48?, 49?, 51?, 52?, 53?, 56?, 57?, 58?, 59?, 60?, 61?, 62?, 63?, 65?, 66?, 67?, 68?, 69?, 71?, 73?, 74?, 75?, 76?, 78?, 79?, 80?, 81?, 83?, 84?, 86?, 87?, 88?, 90?, 91?, 92?, 95?, 96?, 97?, 98?, 99?,
2!, 3!, 4!, 5!, 7!, 8!, 9!, 10!, 12!, 14!, 18!, 19!, 20!, 23!, 27!, 28!, 29!, 30!, 31!, 33!, 34!, 36!, 37!, 38!, 39!, 40!, 41!, 42!, 44!, 47!, 50!, 52!, 53!, 54!, 55!, 58!, 61!, 63!, 64!, 65!, 66!, 67!, 68!, 70!, 72!, 75!, 76!, 77!, 81!, 82!, 83!, 85!, 86!, 89!, 90!, 91!, 93!, 94!, 95!, 99!,

しかし、もっとうまくやれるでしょうか?

ええと、それはあなたがどのようにDRYを取得したいか、そしてあなたがどれだけルールをロジックから切り離したいかに依存すると思います。

このバージョンはactionerクラスを定義します。オーバーロードされた呼び出し演算子はenemy、完全なルールセットが定義されている値に対してのみコンパイルされます。

これはあなたの好みかもしれません。私の考えでは、それはプログラムを非常に切り離し始めているので、それを維持することは作者以外の誰にとっても問題になるかもしれません。

あなたはそれがSuperDRYだと言うかもしれません[ありがとう、私は一週間中ここにいます:-)]

#include <iostream>
#include <array>
#include <random>
#include <algorithm>
#include <cassert>

void do_sth(int i) { std::cout << '!' ; }
void do_sth_else_here(int i) { std::cout << '?'; }

std::array<int, 100> some_array;

// a tag which turns an enemy value into a type, allowing us to easily tag-dispatch our rules.
template<int Enemy>
struct enemy_tag {
    static constexpr int value = Enemy;
};

// A function object that contains all the rules for this action
struct enemy_actioner
{
    constexpr enemy_actioner(std::array<int, 100> const& the_array)
    : _the_array(the_array)
    {}

    // Define logic once

    template<int Enemy, class Pred, class Action>
    void logic(Pred pred, Action action) const
    {
        for (int i = 1 ; i < _the_array.size() ; ++i)
        {
            if (pred(_the_array[i], Enemy))
            {
                std::cout << i;
                action(i);
                std::cout << ", ";
            }
        }
    }

    // Define Rules Once:

    static constexpr auto predicate_for(enemy_tag<1>) { return std::less_equal<>(); }
    static constexpr auto predicate_for(enemy_tag<-1>) { return std::greater_equal<>(); }

    static constexpr auto action_for(enemy_tag<1>) { return &do_sth; }
    static constexpr auto action_for(enemy_tag<-1>) { return do_sth_else_here; }

    // glue logic and rules together through the enemy_tag

    template<int Enemy>
    void operator()(enemy_tag<Enemy> enemy) const
    {
        logic<enemy.value>(predicate_for(enemy), action_for(enemy));
        std::cout << std::endl;
    }

private:
    std::array<int, 100> const& _the_array;
};


void handle_enemy(int enemy)
{
    // introduce our now opaque action object
    enemy_actioner action(some_array);

    // now all we need to do is turn the enemy integer into a tag and the actioner takes
    // care of all the rest. Truly DRY.
    switch (enemy)
    {
        case 1: return action(enemy_tag<1>());
        case -1: return action(enemy_tag<-1>());
        default: assert(!"logic error in program");
    }
}

int main()
{
    std::default_random_engine eng(std::random_device{}());
    std::generate(std::begin(some_array),
                  std::end(some_array),
                  [&eng,
                   dist = std::uniform_int_distribution<int>(-5, +5)]() mutable -> int
                  {
                      return dist(eng);
                  });
    handle_enemy(-1);
    handle_enemy(1);

    return 0;
}

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

オープン/クローズの原則またはストラテジーパターンを使用して、このルビーコードをリファクタリングするにはどうすればよいですか?

分類Dev

DRYの原則に準拠するために、このforループをリファクタリングするにはどうすればよいですか?

分類Dev

マップを使用してkotlinの「When」ロジックをリファクタリングする

分類Dev

戦略パターンでリファクタリングし、SOLID原則を適用する

分類Dev

多くの重複するProducesResponseTypeをリファクタリングして、DRYにします

分類Dev

if条件をリファクタリングして、ifおよびelseブロックのロジックが交換されるようにします。c#

分類Dev

ORロジックを使用して複数の列でjQueryTablesorterをフィルタリングする方法

分類Dev

Pythonロープを使用してモジュールをリファクタリングする方法は?

分類Dev

オープンクローズ原則-プロバイダーへの引数でリファクタリングする方法

分類Dev

Reactフックを使用して機能コンポーネントをリファクタリングする

分類Dev

Rを使用して、Webページのダウンロードファイルボタンを「クリック」するのを模倣します

分類Dev

HOCをフックとしてリファクタリングする

分類Dev

pandas DataFrameからの2つの列のマッピングを使用して、長いif-elseブロックをリファクタリングします

分類Dev

単一責任の原則と移動方法のリファクタリング

分類Dev

ifステートメント内のロジックを最小限にリファクタリングする

分類Dev

ifステートメント内のロジックを最小限にリファクタリングする

分類Dev

ES6を使用してフィルタリングロジックを改善する

分類Dev

Angularui-routerリゾルバーをリファクタリングしてグローバルに使用する

分類Dev

クリーンアーキテクチャの原則を、アダプタデザインパターンとJetpackページングを使用したリサイクラービューページングに適用します

分類Dev

DRYの原則を使用して同じメソッドを実装する2つのタイプのいずれかのオブジェクトを作成する方法

分類Dev

リファクタリングを使用してクラスからジェネリック型を削除する方法

分類Dev

Javaでジェネリックスを使用してファクトリパターンを実装する方法

分類Dev

Rを使用してWebページのダウンロードファイルボタンを「クリック」する

分類Dev

awkを使用してファイルのブロック全体をフィルタリングするにはどうすればよいですか?

分類Dev

匿名プロジェクションを使用してこのメソッドをリファクタリングして、より一般的にするにはどうすればよいですか?

分類Dev

ファンクターを使用してジェネリック型クラス関数を作成する方法

分類Dev

reactを使用してオブジェクトの配列をループするためのコードをリファクタリングする方法は?

分類Dev

RubyメソッドをリファクタリングしてRubocopテストに合格すると同時にDRYである方法

分類Dev

Visual Studio Codeを使用してローカル変数名をリファクタリングする

Related 関連記事

  1. 1

    オープン/クローズの原則またはストラテジーパターンを使用して、このルビーコードをリファクタリングするにはどうすればよいですか?

  2. 2

    DRYの原則に準拠するために、このforループをリファクタリングするにはどうすればよいですか?

  3. 3

    マップを使用してkotlinの「When」ロジックをリファクタリングする

  4. 4

    戦略パターンでリファクタリングし、SOLID原則を適用する

  5. 5

    多くの重複するProducesResponseTypeをリファクタリングして、DRYにします

  6. 6

    if条件をリファクタリングして、ifおよびelseブロックのロジックが交換されるようにします。c#

  7. 7

    ORロジックを使用して複数の列でjQueryTablesorterをフィルタリングする方法

  8. 8

    Pythonロープを使用してモジュールをリファクタリングする方法は?

  9. 9

    オープンクローズ原則-プロバイダーへの引数でリファクタリングする方法

  10. 10

    Reactフックを使用して機能コンポーネントをリファクタリングする

  11. 11

    Rを使用して、Webページのダウンロードファイルボタンを「クリック」するのを模倣します

  12. 12

    HOCをフックとしてリファクタリングする

  13. 13

    pandas DataFrameからの2つの列のマッピングを使用して、長いif-elseブロックをリファクタリングします

  14. 14

    単一責任の原則と移動方法のリファクタリング

  15. 15

    ifステートメント内のロジックを最小限にリファクタリングする

  16. 16

    ifステートメント内のロジックを最小限にリファクタリングする

  17. 17

    ES6を使用してフィルタリングロジックを改善する

  18. 18

    Angularui-routerリゾルバーをリファクタリングしてグローバルに使用する

  19. 19

    クリーンアーキテクチャの原則を、アダプタデザインパターンとJetpackページングを使用したリサイクラービューページングに適用します

  20. 20

    DRYの原則を使用して同じメソッドを実装する2つのタイプのいずれかのオブジェクトを作成する方法

  21. 21

    リファクタリングを使用してクラスからジェネリック型を削除する方法

  22. 22

    Javaでジェネリックスを使用してファクトリパターンを実装する方法

  23. 23

    Rを使用してWebページのダウンロードファイルボタンを「クリック」する

  24. 24

    awkを使用してファイルのブロック全体をフィルタリングするにはどうすればよいですか?

  25. 25

    匿名プロジェクションを使用してこのメソッドをリファクタリングして、より一般的にするにはどうすればよいですか?

  26. 26

    ファンクターを使用してジェネリック型クラス関数を作成する方法

  27. 27

    reactを使用してオブジェクトの配列をループするためのコードをリファクタリングする方法は?

  28. 28

    RubyメソッドをリファクタリングしてRubocopテストに合格すると同時にDRYである方法

  29. 29

    Visual Studio Codeを使用してローカル変数名をリファクタリングする

ホットタグ

アーカイブ