0

例えば...

if( (stuCourses.contains("crs101") && stuCourses.contains("crs102") && 
    stuCourses.contains("crs103"))  || (stuCourses.contains("crs201") && 
    stuCourses.contains("crs202")) || stuCourses.contains("crs300") )
{
    //then student can register for crs301;
}

また、このようなもの、つまりコース/コースの前提条件に最適なテーブル スキーマは何ですか...「および/または」ロジックを処理するためにテーブル フィールドをどのように構造化しますか?

4

4 に答える 4

1

次のテーブルがあります。これは少し複雑なので、これが小さな実装であれば、上記のようにコードを更新するだけで簡単になるかもしれません!

Courses(ID, Name, ...)
-- Information about each course

CoursePrerequisiteRules(ID, CourseID, PrerequisiteRuleID, ValidFrom, ValidTo)
-- Assigns a single rule to a particular course, for a particular range of academic years

PrerequisiteRules(ID, RuleType)
-- The header record defining a rule or sub-rule for a specific course

PrerequisiteRuleCourseMembers(ID, PrerequisiteCourseID, PrequisiteRuleID)
-- Each record assigns one course to a prerequisite rule.

PrerequisiteRuleRuleMembers(ID, ParentPrerequisiteRuleID, ChildPrerequisiteRuleID)
-- Each record assigns one prerequisite rule as a child of another rule

PrerequisiteRules.RuleType は「AND」または「OR」になります。前提条件ルールには、PrerequisiteRuleCourseMembers を使用してコースを割り当てるか、PrerequisiteRuleRuleMembers を使用して他のルールを割り当てることができます。各コースは一度に 1 つのルールをアクティブにしますが、これらは必要に応じて学年ごとに定義できます (CoursePrequisiteRules の ValidFrom と ValidTo を使用)。この 1 つのルールのサブルールとして、ルールの複雑なツリーを作成できます。

たとえば、CS320 が必要とする要件 (CS101 または CS102) と MT101 を述べるには:

Courses
ID  Name
1   CS101
2   CS102
3   MT101
4   CS320

CoursePrerequisites
ID  CourseID PrerequisiteRuleID  ValidFrom  ValidTo
5   4        7                   2010       2012
-- The rule for CS320 between 2010 and 2012 is rule number 7

PrerequisiteRules
ID  RuleType
6   "OR"
7   "AND"
-- Rule number 7 performs an AND on all its children
-- Rule number 6 uses an OR instead

PrerequisiteRuleCourseMembers
ID  PrerequisiteCourseID   PrequisiteRuleID
8   1                      6
9   2                      6
10  3                      7
-- This assigns CS101 and CS102 to rule 6, meaning that rule 6 should be evaluated as
-- CS101 OR CS102. It also assigns MT101 to rule 7.

PrerequisiteRuleRuleMembers
ID  ParentPrerequisiteRuleID ChildPrerequisiteRuleID
11  7                        6
-- This assigns Rule 6 to Rule 7, so with the row in the previous table, rule 7 becomes
-- MT101 AND [Rule 6]
-- ...which means MT101 AND (CS101 OR CS102) 
于 2012-07-11T19:42:57.700 に答える
0

これを実現する最善の方法は、アプリケーションのアーキテクチャとニーズに応じて、データベースまたはハード ファイルのいずれかに、XML で「前提条件ルール」を格納することです。XML は、次のような前提条件セットを保存できるため、ニーズに適しています。

<Courses>
    <Course>
        <CourseCode>crs301</CourseCode>
        <PrereqSets>
            <PrereqSet>
                <CourseCode>crs101<CourseCode>
                <CourseCode>crs102<CourseCode>
                <CourseCode>crs103<CourseCode>
            </PrereqSet>
            <PrereqSet>
                <CourseCode>crs201<CourseCode>
                <CourseCode>crs202<CourseCode>
            </PrereqSet>
            <PrereqSet>
                <CourseCode>crs300<CourseCode>
            </PrereqSet>
        </PrereqSets>
    </Course>
    <Course> 
    <!--Some other course data goes here-->
    </Course>
</Courses>

その後、XPath を使用して、XML データから非常に簡単にクエリを実行できます。

もちろん、データをデータベースに保存するだけでこれを達成する方法は他にもあります。そのような方法の 1 つは、以下のような複合キーを使用して連想テーブルに格納することです...

Course table
    CourseID, Name
    1, crs101
    2, crs102
    3, crs103
    4, crs201
    5, crs202
    6, crs300
    7, crs301


CoursePrereqMap table
    CourseID, PrereqSetID, PrereqCourseID
    7, 1, 1
    7, 1, 2
    7, 1, 3
    7, 2, 4
    7, 2, 5
    7, 3, 6

どのような方法でも、前提条件セットをカスタム オブジェクト (古い用語でなければ VO または DTO) にロードするか、ある種のリストまたは配列にロードして、前提条件セット全体を処理するメソッドを記述できます。 、または前提条件セットのリストまたは配列でさえあり、すべてのコースが少なくとも 1 つのセットを完了していることを確認します。

これが、そのようなデータを保存する方法に関する 2 番目の質問の答えになることを願っています。これは具体的な答えではなく、それを実装するためのいくつかの方法についての提案です。もちろん、あなたが取ることができるアプローチはたくさんあります。

于 2012-07-12T00:50:49.773 に答える
0

正直なところ、変更する必要があるのは条件自体ではないと思います...それによって表される抽象化のレベルだけです。これは面倒に思えます:

if((stuCourses.contains("crs101") && stuCourses.contains("crs102") && stuCourses.contains("crs103")) || (stuCourses.contains("crs201") && stuCourses.contains("crs202")) || stuCourses.contains("crs300") )
{
    //then student can register for crs301;
}

しかし、あなたが考える理由ではありません。and/or ロジックは見栄えを良くするためにフォーマットできますが、もっと重要なのは、別の関数に抽象化する必要があることです。このようなもの:

public void RegisterStudentForCRS301()
{
    // other stuff
    if (StudentHasTakenNecessaryCourses())
    {
        // etc.
    }
}

private bool StudentHasTakenNecessaryCourses()
{
    return
        StudentHasTakenNecessary100LevelCourses() ||
        StudentHasTakenNecessary200LevelCourses() ||
        StudentHasTakenNecessary300LevelCourses()
    ;
}

private bool StudentHasTakenNecessary100LevelCourses()
{
    return
        stuCourses.contains("crs101") &&
        stuCourses.contains("crs102") &&
        stuCourses.contains("crs103")
    ;
}

private bool StudentHasTakenNecessary200LevelCourses()
{
    return
        stuCourses.contains("crs201") &&
        stuCourses.contains("crs202")
    ;
}

private bool StudentHasTakenNecessary300LevelCourses()
{
    return
        stuCourses.contains("crs300")
    ;
}

各関数には独自の抽象化レベルがあり、1 つのことだけを担当します。関数は、複数の抽象化レベルにわたってロジックをチェックする高レベル関数に集約されます。そして、それはすべて公開機能に集約され、詳細は気にせず、ビジネス コンセプトを知る必要があるだけです (学生は資格がありますか?)。

抽象化の各レベルは読みやすく、理解しやすいものです。何&&||意味するかについての基本的な説明があれば、ロジックを読むのにプログラマーである必要さえありません。確かに、それはより多くのコードです。しかし、それが何をしているかを不確かな言葉で非常に明確に説明するのは、表現力豊かなコードです。ロジックの詳細に関心がなく、ビジネスの高レベルな機能だけを知りたい場合は、比較ロジックを見る必要さえありません。適切な名前の関数を呼び出すだけです。下位レベルの抽象化で下位の詳細を処理します。

于 2012-07-11T18:11:47.490 に答える