コール階層に関する問題

関数/メソッドをカスケーディングスタイルで呼び出す状況があります。説明と質問については、次の例を参照してください。私はこの状況の技術的な言葉を知りたがっています。人々が私が何を話しているのかを理解することはより簡単になります。

public static class test
{
    private void button1_Click(object sender, RoutedEventArgs e)
    {
        if (Login("johndoe","password")) 
        {
            if(checkForSomething("johndoe"))
            {
                DoOpenDashboard();

               //Now it opens dashboard, it has several buttons. 
               //Each button does several different things
               //On this example I am just giving you two level of hierarchy
               //but in my actual program, there are 7 levels.
            }
        }
    }

    public static bool Login(string userid, string password)
    {
        //valid user
        return true;
    }

    public static bool checkForSomething(string userid) 
    {
        return true;
    }

子メソッドが正常に実行された場合、以前の呼び出しメソッド/関数に戻るプロセスを回避するにはどうすればよいですか?

たとえば、ログインメソッドは checkForSomething( "johndoe")を呼び出しています。 checkForSomething( "johndoe")が渡された場合、DoOpenDashboardを呼び出してDashboardウィンドウを開きます。この時点で私のプロセスはcheckforsoemthingに戻り、ログインするべきではありません。それが理にかなってほしい。

1
あなたが求めていることが(簡単に)実行できるとしても、あなたはそれを何回呼んだかに基づいて異なった振る舞いをすることによって、単一責任原理に違反します。確かにシステムを維持することは難しいでしょう。
追加された 著者 R0MANARMY,
あなたの質問は非常に理解しにくいです。クラスに静的変数またはインスタンスメンバーを追加して、ユーザーが既にログインしているかどうかを示すだけでなく、そのブール値がfalseの場合は Login()
追加された 著者 Kiley Naro,
それを含むクラスと同じ名前のメソッドを持つことはできません。
追加された 著者 Miguel Angelo,
コードブロックの外に質問を移動してください...今のように読むのは不可能です。
追加された 著者 Miguel Angelo,

2 答え

あなたがここで何を求めているのかは分かりません。あなたの疑似コードは、あなたのクラスのコンストラクタで呼び出されているLogin()メソッドを示しています。これが本当にあなたのコードがどのように動作しているのであれば、再びLoginを呼び出すのを防ぐために、このクラスの新しいインスタンスの作成を避ける必要があります。

しかし、私はあなたが本当に矢のアンチパターンについて尋ねていると思います:

http://codinghorror.com/blog/2006/01/flattening-arrow -code.html

EDIT

I was trying to avoid copy & paste, but since the original post seems not to have been clear enough, here's a selection from Coding Horror as linked above:

Where appropriate, I flatten that arrow code by doing the following:

  1. Replace conditions with guard clauses. This code..

    if (SomeNecessaryCondition) { //function body code }

    .. works better as a guard clause:

    if (!SomeNecessaryCondition) { throw new RequiredConditionMissingException; } //function body code

(他のテクニックも掲載されていることに注意してください。しかし、私はこの最初のもので十分でしょう)

このようにして、チェックが失敗すると、メソッド呼び出しが失敗した場合、それぞれの追加チェックで別のネストされたチェックが行われることはありません。これは、button1_Clickがbool(成功の場合はtrue、失敗の場合はfalse)を返す関数を呼び出し、失敗した場合はfalseを返すことによって例外をスローすることなく行うこともできます。

private void button1_Click(object sender, RoutedEventArgs e)
{
    if (AllSystemsGo())
    {
        DoOpenDashboard();
    }
}

private bool AllSystemsGo()
{
    if (!Login("johndoe","password"))
        return false;

    if (checkForSomethingEvil("johndoe"))
        return false;

    if (!checkForSomethingImportant())
        return false;

    return true;
}
0
追加された
明らかにどちらか一方ではありません。明らかにこれはコードをコンパイルしていないので、戻り値が間違っているのか、メソッド名が間違っているのか、あなたの推測と同じくらい良いです。
追加された 著者 sq33G,
これはコンストラクタではなく、クラスと同じ名前のメソッドです(戻り型があることに注意してください)。
追加された 著者 R0MANARMY,
私は可能な限り、「矢印コードを平坦化する」で述べたようにコンティニュイティチェックを使用しています。私はコードvb6コードからビジネスロジックを抽出しています。私はビジネスロジックを抽出して理解しているので、私は恐ろしい状況に陥っています。
追加された 著者 Shai,

あなたのメソッドが一度だけチェックされていることを確認しようとしていますか?おそらく、いくつかのプロパティを複数回クエリする必要があるかもしれませんが、一度だけテストします。

private bool? canLogin;
private bool? somethingOk;

private bool CanLogin
{
    get
    {
        if (canLogin == null)
            canLogin = Login("johndoe","password");
        return canLogin.Value;
    }
}

private bool SomethingOk
{
    get
    {
        if (somethingOk == null)
            somethingOk = checkForSomething("johndoe");
        return somethingOk .Value;
    }
}

private void button1_Click(object sender, RoutedEventArgs e)
{
    if (this.CanLogin && this.SomethingOk &&//other checks) 
    {
        DoOpenDashboard();            
    }
}
0
追加された