1

情况是我有这个界面:

interface ISymbol
{

}

和这些类:

class Letter implements ISymbol
{

}

class Number implements ISymbol
{

}

class LowerCaseLetter extends Letter
{

}

class UpperCaseLetter extends Letter
{

}

现在让我们说我有这个功能,在不同的班级。此类执行的逻辑不属于 ISymbol 类的实现:

class SymbolMonitor
{
void func(ISymbol[] symbols)
{
    for (ISymbol iSymbol : symbols)
    {
        // If the symbol is a number 
        // or a lower case letter do something.
    }
}
}

但我不想专门检查这两种类型,因为我可能还有其他实现类的 ISymbol 也需要相同的逻辑。

我的问题是关于首选的行动方式。我有两个解决这个问题的方法。1. 创建一个这样的:

enum SymbolType
{
    NORMAL,
    SPECIAL1,
    SPECIAL2,
}

并添加到代码中:

    interface ISymbol
{
    SymbolType getType();
}

class SymbolMonitor
{
    void func(ISymbol[] symbols)
{
    for (ISymbol iSymbol : symbols)
    {
            if(iSymbol.getType().equals(SymbolType.SPECIAL1))
                    {
                        // Do special1 logic
                    }
            if(iSymbol.getType().equals(SymbolType.SPECIAL2))
                    {
                        // Do special2 logic
                    }
    }
}
}
  1. 我可以创建空接口并使用 instanceof 函数。

    interface ISpecialSymbol1
    

    {

    }

    接口 ISpecialSymbol2 {

    }

    类 LowerCaseLetter 扩展字母实现 ISpecialSymbol1 {

    }

    类号实现 ISymbol, ISpecialSymbol1 {

    }

这样功能将是:

class SymbolMonitor
{
void func(ISymbol[] symbols)
{
    for (ISymbol iSymbol : symbols)
    {
        if(iSymbol instanceof ISpecialSymbol1)
        {
            // Do special 1 logic.
        }
        if(iSymbol instanceof ISpecialSymbol2)
        {
            // Do special 2 logic.
        }
    }
}
}

我认为第二个选项要简单得多,但我是 java 新手,我完全不确定使用的正确方法是什么。

4

2 回答 2

2

在接口中声明一个方法:

interface ISymbol
{
   public void doSomething();
}

并且任何实现类都可以覆盖并指定它们所需的行为。在这种情况下:

class Letter implements ISymbol
{
    public void doSomething() {
         //do Nothing
    }
}

class Number implements ISymbol
{
     public void doSomething() {
         //do Something
    }
}

class LowerCaseLetter extends Letter
{
    public void doSomething() {
         //do Something
    }
}

class UpperCaseLetter extends Letter
{
    public void doSomething() {
         //do Nothing
    }
}

然后你可以直接调用 ISymbol.doSomething()

void func(ISymbol[] symbols)
{
    for (ISymbol iSymbol : symbols)
    {
        iSymbol.doSomething()
    }
}
于 2013-09-22T13:46:16.390 回答
1

您的问题是对“设计模式:可重用的面向对象软件的元素”中访问者模式的动机的逐字引用。在代码中,这将类似于:

interface Visitor {
    void visit(Letter letter);
    void visit(Number number);
    // ...
}

interface ISymbol {
    void visit(Visitor v);
}

class Letter {
    @Override void visit(Visitor v) {
        v.visit(this);
    }
}

class Number {
    @Override void visit(Visitor v) {
        v.visit(this);
    }
}

如果访问者可以不知道他们操作的类型(因为访问者只使用所有符号都有的方法),那么使用枚举是一个可行的选择。如果访问者确实需要转换为相应的符号类型,我更喜欢访问者模式。

我通常更喜欢访问者模式而不是一系列 instanceof 检查,因为访问者模式使编译器能够验证所有访问者处理所有符号类型 - 因此,如果您添加符号类型,所有现有访问者将不再编译,直到您指定如何处理这种新类型。

于 2013-09-22T14:23:43.070 回答