访问者模式的两个参数

这是一个问题陈述:我们有接口/超级班的学生和老师

学生有两个实施/分类,ScienceStudent和PhysicalEducationStudent

教师有科学教师和物理教育教师。

我们想要实现一种方法getMeetingPoint(Student,Teacher t),它根据学生和教师的类型返回他们见面的地方。

举例来说,如果其ScienceStudentScienceTeacher他们在实验室会面,如果PEStudent体育教师 ,他们在地面上,如果其ScienceStudent体育教师或反之亦然见面时,他们在餐厅见面

我们可以编写一个简单的方法,使用instanceof进行检查。 但问题是,当教师或学生得到延伸并且难以维护时,这变得复杂。 像这样的东西:

public class MeetingPointDecider {

    getMeetingPoint(Student s,Teacher t) {
        if(s instanceof ScienceStudent && t instanceof ScienceTeacher) {
            return "Lab";
        } else if (s instanceof PhysicalEducationStudent && t instanceof PhysicalEducationTeacher) {
            return "GRound";
        }
        .
        .
        .
    }
}

另一种选择是编写一个工厂,该工厂接受学生和教师并返回类似于MeetingPointDecision [地面或实验室]的东西,但问题依然存在。 有什么好的模式可以使用,当我们添加一个新类时,我们不需要修改现有的类(或者最小的修改)。比如说Science的instanceof我们有ChemistryStudent,PhysicsStudent和ChemistryLab,PhysicsLab。 还可以添加更多的动作,这些动作在学生和教师类型的实现方面有所不同(“访问者”是一个选项,但不确定如何使用两个决策类实现)

有人可以建议一个好的方法来实现这一点?

谢谢!


我会用地图解决这个问题。 关键应该确定教师与学生的组合,价值就是交汇点。 对于关键我会结合类名。 解决方案如下:

public class MeetingPointDecider
{
    public enum MeetingPoint { Ground, Lab, Cafeteria }
    private static MeetingPoint defaultmp = MeetingPoint.Cafeteria;
    private static Map<String, MeetingPoint> studentTeacherCombinations = new HashMap<>();

    static {
        studentTeacherCombinations.put(getMapKey(ScienceTeacher.class, ScienceStudent.class), MeetingPoint.Lab);
        studentTeacherCombinations.put(getMapKey(PETeacher.class     , PEStudent.class)     , MeetingPoint.Ground);
    }

    public static MeetingPoint getMeetingPoint(Student s,Teacher t)
    {
        String mapKey = getMapKey(t.getClass(), s.getClass()); 
        return studentTeacherCombinations.containsKey(mapKey) ? 
          studentTeacherCombinations.get(mapKey) : defaultmp; 
    }

    private static String getMapKey (Class<? extends Teacher> tCls, Class<? extends Student> sCls)
    {
        return tCls.getName() + "_" + sCls.getName();
    }
}

逻辑部分位于地图填充的静态ctor中。 支持未来的课程很容易。


这是一个有趣的话题,因为最近Eric Lippert撰写了一篇文章来讨论这个问题。 它分为五个部分:

  • 第一部分
  • 第二部分
  • 第三部分
  • 第四部分
  • 第五部分
  • 代码是用C#语言编写的,但我认为从Java的角度来看应该是可以理解的,至少。

    总之,你不会得到更好的结果与工厂或访客模式。 您的MeetingPointDecider实施已经按计划进行。 如果您仍然需要一些硬编码或映射较少的东西,请尝试sharonbn的解决方案或类似方法。

    或者如果你需要可扩展的规则,你可以尝试类似Decorator模式的东西:

    public class MeetingPointDecider {
        // the rules, you can add/construct it the way you want
        Iterable<MeetingPointDeciderRule> rules;
        string defaultValue;
        getMeetingPoint(Student s,Teacher t) {
            string result;
            for(MeetingPointDeciderRule rule : rules){
                result = rule.getMeetingPoint(s, t);
                //check whether the result is valid and not null
                //if valid, return result
            }
            //if not valid, return default value
            return defaultValue;
        }
    }
    
    //this can be easily extended
    public abstract class MeetingPointDeciderRule {
        getMeetingPoint(Student s,Teacher t) {
    
        }
    }
    

    最后但不推荐,但如果您仍然需要灵活性,您可以尝试运行时编译该类并将其用作规则引擎。 但不推荐。

    注意:我没有回答原来的问题,因此社区维基答案。 如果此答案格式错误,我会将其删除。


    如果向接口(学生和教师)添加getMeetingKeyPart()方法并实施以返回每个学生和教师实施的特定关键部分,会怎么样?

    例如ScienceStudent返回“ScienceStudent”,ScienceTeacher返回“ScienceTeacher”。

    然后,您可以定义一个.properties文件,其中为任何所需的组合键定义了会议点。 例如

    ScienceStudent-ScienceTeacher=Lab
    PhysicalEducationStudent-PhysicalEducationTeacher=Ground
    ...
    

    如果没有匹配的组合键,则返回“自助餐厅”

    链接地址: http://www.djcxy.com/p/26473.html

    上一篇: Visitor Pattern for two arguments

    下一篇: InfiniteScroll Not Working