面向对象编程正确使用接口



我正在尝试为游戏设计一些类,但我不确定我做得对。

我有两个类:ActorBuilding。它们有几个子类:PolicemanFiremanPoliceStationFireStation

我希望能够将所有这些项放在一个列表中,以便稍后进行迭代,所以我添加了一个基类:GameEntity
所以我有这个:

public abstract class GameEntity: 
{
public GameEntity()
{
}       
}
public class Actor: GameEntity
{
public int _speed;
public TileSprite _UI;
public Actor()
{
}
public bool CollidesWith(Vector2 pos)
{
//Do stuff here
}
public virtual void OnClick()
{
//Do stuff here
}
public void DoActing()
{
}
}
public class Policeman: Actor
{
public Policeman()
{
_speed = 10;
}
public override void OnClick()
{
//Do stuff
}
}
public class Building: GameEntity
{
public TileSprite _UI;
public Building()
{
}
public bool CollidesWith(Vector2 pos)
{
//Do stuff here
}
public virtual void OnClick()
{
//Do stuff here
}
public void DoBuilding()
{
}
}
public class PoliceStation: Building
{
public PoliceStation()
{
}
public override void OnClick()
{
//Do stuff
}
}

现在,我想能够做到这一点:

List<GameEntity> Entities = new List<GameEntity>();
Actor a1 = new PoliceMan();
Building b1 = new PoliceStation
Entities.Add(a1);
Entities.Add(b1);
foreach(GameEntity ent in Entities)
{
if (ent.CollidesWith(something))
{
ent.OnClick();
//If Actor then do 
ent.DoActing();
//If Building then do
ent.DoBuilding();
}
}

现在,为了完成最后一点,我最好实现一个包含OnClickCollidesWith的接口,还是可以通过继承来实现?如果是,我该怎么做?

干杯。

这只是给你一个想法,我想这正是你所需要的。

public interface IGameEntity
{
bool CollidesWith();
void OnClick();
void DoActing();
}
public class Actor : IGameEntity { //Interface implemented }
public class Building: IGameEntity { //Interface implemented }
public class Policeman: IGameEntity { //Interface implemented }
public class Fireman: IGameEntity { //Interface implemented }
public class FireStation: IGameEntity { //Interface implemented }

在您的客户端对象中,只需执行以下操作:

List<IGameEntity> entities = new List<IGameEntity>()
{
new Actor(), 
new Building(), 
new Policeman(), 
new Fireman(), 
new Fireman()
};
foreach (IGameEntity entity in entities)
{
entity.CollidesWith();
entity.OnClick();
entity.DoActing();
}

这里有很多方法。如果所有GameEntities都可以点击,那么你可以在基类中添加一个OnClick事件属性。

如果不是,那么我会有一个Interface IClick,然后在可点击的实体上实现它。

碰撞,取决于。建筑物不会移动,所以它们不会与任何东西碰撞,但它们可能会被碰撞,因此,例如,你可能想做一个损坏的rountine,这意味着一个被破坏的、例行的——也许是维修例行的。

没有正确的答案,但是三种代码气味将是一个没有任何内容的基类。

一个非常深刻的继承层次(在我的书中,两个以上的层次令人怀疑)因此,如果你开始看到GameEntity->BuildingEntity->ActiveBuildingEntity->RepairableBuildingEntity,你就会陷入更混乱的境地。

最重要的是,一个基类中有无所事事的方法,这些方法之所以存在,是因为您需要在某些子体中添加行为(覆盖)。

不要害怕有几个接口。IClick、ICollsion、IDamage、IRepair等。这比暗示建筑物会撞到汽车要好得多。

您可以这样做:

public interface IGameEntity
{
void OnClick();
bool CollidesWith(Vector2 pos);
void Do();
}
public abstract class Actor: IGameEntity
{
public int _speed;
public TileSprite _UI;
public virtual bool CollidesWith(Vector2 pos)
{
//Do stuff here
}
// can be marked virtual with implementation if you want a default
// this way base classes will be forced to implement their own implementation
public abstract void OnClick();
// can be marked virtual with implementation if you want a default
// this way base classes will be forced to implement their own implementation
public abstract void Do();
}
public class Policeman: Actor
{
public Policeman()
{
_speed = 10;
}
public override void OnClick()
{
//Do stuff
}
public override void Do()
{
//Do Acting for Police
}
}
public abstract class Building: IGameEntity
{
public TileSprite _UI;
public bool CollidesWith(Vector2 pos)
{
//Do stuff here
}
public abstract void OnClick();
public abstract void Do();
}
public class PoliceStation: Building
{
public PoliceStation()
{
}
public override void OnClick()
{
//Do stuff
}
public override void Do()
{
// Do Building
}
}

如果游戏实体只是一个接口,那么就没有必要把它变成一个抽象类。如果演员和建筑永远不能作为一个独立的物体存在,那么它们应该是抽象的。如果基类必须重写DoActing、DoBuilding和OnClick,则可以在actor和Building中将它们标记为抽象。

我遵循了norlesh的建议,只使用一个方法Do。你也可以让Actor和Building有自己的抽象方法,而IGameEntity没有Do。然后你会放一个if语句,检查每个对象是否都是builder类型,然后他们会运行build,如果是Actor类型,然后运行act。

我认为有一种方法的方式更好,因为你只需要消除一个步骤。从设计的角度来看,我不确定,但无论哪种方式对我来说都是一样的。

List<IGameEntity> Entities = new List<IGameEntity>();
Actor a1 = new PoliceMan();
Building b1 = new PoliceStation();
Entities.Add(a1);
Entities.Add(b1);
foreach(IGameEntity ent in Entities)
{
if (ent.CollidesWith(something))
{
ent.OnClick();
ent.Do();
}
}

将虚拟doStuff()添加到GameEntity并在子类中重写它,而不是使用像DoActingDoBuilding这样的唯一方法名,然后从循环中调用它应该可以满足您的需要。

最新更新