3

当我想这样做时,我遇到过几种情况。这可能是一个例子:

考虑国际象棋游戏的可能实现。我们定义了抽象类 'Piece' 和继承自它的类:'bishop' 'peon' 'tower' 'horse' 'queen' 等

我们可能让我们的 peon 即将到达棋盘的尽头,并且可能需要调用该 peon 对象的方法来将该对象的类更改为“Queen”、“horse”或其他任何东西。

所以我的问题是,有没有办法在 C++ 或 Java 中做到这一点?如果没有,用任何其他语言?另外,一般情况下还有其他方法吗?

4

6 回答 6

10

在像 C++ 或 Java 这样的语言中,我会创建一个新的“Queen”或“Horse”实例,并用那个新实例替换“Peon”实例。

于 2012-06-29T13:02:19.463 回答
2

我认为您对对象的想法与对象的使用方式相混淆。在面向对象的语言中,我们有指示对象实例的内存位置的指针:

Piece pointerToPieceObject = new Peon();

在上面的语句中,pointerToPieceObject是 "type" Piece。因为PeonQueen都继承自Piece,所以这个指针可以指向以下任何类型的对象实例:

pointerToPieceObject = new Queen();

这是任何面向对象语言都支持的非常普遍的概念。这些语言之间的唯一区别是处理类型的方式(例如 Python 与 Java)。这个概念被称为多态性,可以用来做比上面的例子更有趣的事情:http ://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming

于 2012-06-29T13:08:36.780 回答
0

您也许可以使用装饰器模式策略模式

带装饰器:

interface ChessPiece {
    Set<Move> getPossibleMoves();
    Image getAppearance();
}

class Pawn implements ChessPiece {
    ...
}

class Decorator implements ChessPiece {
    ChessPiece decorated;

    public Decorator(ChessPiece decorated_) {
        this.decorated = decorated_;
    }

    @override
    Set<Move> getPossibleMoves() {
        Set<Move> result = decorated.getPossibleMoves();
        // alter result
        return result;
    }
}

需要时,您将Pawn实例替换为Decorated实例。 因此,它仍然涉及用OpenSause 的回答中提到的另一个实例替换一个实例。

ChessPiece pawn = new Pawn;
...
pawn = new Decorated(pawn);

当您提前计划时,您可以使用 strategy它仍然没有真正改变类

interface PossibleMovesStrategy {
    Set<Move> getPossibleMoves();
}

interface AppearanceStrategy {
    Image getAppearance();
}

class ChangingChessPiece extends ChessPiece {
    PossibleMovesStrategy posMoves;
    AppearanceStrategy appearance;

    @override
    Set<Move> getPossibleMoves() {
        return posMoves.getPossibleMoves();
    }

    @override
    Image getAppearance() {
        return appearance.getAppearance();
    }
}
于 2012-06-29T13:01:28.753 回答
0

我看到两个简单的选择:

  1. type一个字段设置为// ...Pice的实例(可能是单例,例如实现为枚举),这样您就可以轻松更改它。BishopQueen

  2. 只需删除Peon并在其位置创建一个新的Queen/ Horse/... 即可。我不认为对象身份在这里非常重要。

于 2012-06-29T13:04:06.917 回答
0

简短的回答是否定的,您不能更改对象的类。您需要将其替换为所需类的新对象。

于 2012-06-29T13:04:07.517 回答
0

对于通用的基本类“升级”或“演变”到更高、更定义的类的情况,您可能希望所有定义更明确的类(Knight、Queen、Bishop)都有一个采用 Peon 类的构造函数,在这种情况下,典当。如果 Pawn 和 Knight 和 Queen 以及所有棋子都有一个共同的基础,那么在 Knight/Queen/etc 的构造函数中,您将可以访问该基类中的受保护变量,并且可以将 Pawn 克隆到下一个类中。

class Pawn extends ChessPiece {...}

class Queen extends ChessPiece {
    public Queen(Pawn p) {
        // DON'T accept a ChessPiece unless you want
        // knights or rooks to become queens.

        // copy p's variables here
    }
}

ChessPiece piece= new Pawn();
// Sometime later...
if (piece is Pawn)
    piece = new Queen((Pawn)piece);

这与您可能能够更改班级一样接近。

于 2012-06-29T15:19:14.077 回答