在C#与替代

时间:2015-04-27 18:29:00

标签: c# oop object reflection instanceof

我在使用C#制作的游戏中遇到了一个问题。这是一个简单的基于平铺的匹配游戏,问题出现在我试图制造的电源上:

假设我们有基本的瓷砖类型,圆形正方形和菱形,它们都是瓷砖的子类。我试图将“匹配”行为提取到抽象的Tile方法,而不是让圈子只与圈子匹配:canMatchWith(Tile t)。 Tiles还有两种方法来添加/删除它们可以匹配的Tiles。

所以说我们在游戏中间有一个圆形瓷砖,我们有一个补充说“圆形瓷砖本回合可以与方形瓷砖匹配”。我将浏览所有Circle图块并说出circleTile.addCanMatchWith(typeof(Square))。在内部,我们有一个List canMatchWith。

然后,我想说“圆圈不能再与正方形匹配”,只需说circleTile.removeCanMatchWith(typeOf(Square))。

这是我目前的解决方案,它的效果很好,没有我注意到的性能缺陷(这是一个基于区块的匹配游戏,所以这些类型每个'移动'只评估一次,而不是逐帧评估)。然而,我脑中的声音告诉我,这是完成这种行为的一种不好的方法。所以我有一些选择:

  1. 枚举......每个Tile可以用Tiletype类型变量组成。这将在构造函数中初始化,并设置为Type.SQUARE用于方块,依此类推。然后,每个Tile都有一个List canMatchWith,功能与我原来的实现相同。除了这种情况,它有点棘手。假设我有一些圆形子类,椭圆形和椭圆形。我希望椭圆能够与ONLY方格匹配,但是elipses可以匹配所有圆圈而不是正方形。
  2. 这里的问题是冗余,我的枚举现在也有OVAL和ELIPSE,并且Elipse类将具有(CIRCLE,OVAL,ELIPSE TileTypes)作为它可以匹配的类型。这完全是多余的,我想只说“Circle”,我可以用类型。我想Tiles可以有TileType baseType和TileType actualType。

    1. 某种形式的行为构成。忘记Tile子类,只为Tiles方法和List的实例变量。然后,在运行时我们可以说someTile.addCanMatch(new CircleMatchBehavior())。这看起来很愚蠢,因为我会有一堆课程只是说你可以匹配特定的形状。
    2. 总之,我想要实现的是让多个对象类型能够与任意数量的不同类型进行交互。问题是,我应该为Type使用什么。可以在这里使用GetType吗?枚举?或者有人会推荐更好的策略吗?我试图尽可能通用,这些磁贴不应该在其他磁贴上有任何硬编码依赖,并且必须能够在运行时更改他们可以与之交互的人。假设我创建了一个新的Tile子类,五角形......好吧,Pentagons可以与Squares,Circles和Pentagons匹配。我的实现很简单,但有些东西告诉我这是一个肮脏的OOP练习。

      我觉得我必须使用Types / Enums,因为我不是想说这个Tile.addCanMatch(Tile someOtherObject)。这太具体了,我希望thisTile能够与作为特定类的实例的所有tile匹配。

2 个答案:

答案 0 :(得分:2)

如果类似类型的所有形状总是共享行为,那么将该行为存储在每个实例上是有意义的,'水平。相反,你可以拥有一个' CanMatchManager,'存储由形状类型索引的列表字典。然后,当圆圈试图比较匹配时,它会从MatchManager请求它可以匹配的类型。或者,MatchManager可以接收两个形状,并确定它们是否匹配。这是Mediator Pattern

答案 1 :(得分:2)

我知道这个问题已经得到了回答和接受,但我曾经做过类似的事情,我想我只是在这里发布代码。

    public class TypeMatchManager
    {
        private Dictionary<Type, List<Type>> savedMatches = new Dictionary<Type, List<Type>>();

        public TypeMatchManager() { }

        public void AddMatch(Type firstType, Type secondType)
        {
            this.addToList(firstType, secondType);
            this.addToList(secondType, firstType);
        }

        public void DeleteMatch(Type firstType, Type secondType)
        {
            this.deleteFromList(firstType, secondType);
            this.deleteFromList(secondType, firstType);
        }

        public bool CanMatch(Type firstType, Type secondType)
        {
            List<Type> firstTypeList = this.findListForType(firstType);
            List<Type> secondTypeList = this.findListForType(secondType);
            return (firstTypeList.Contains(secondType) || secondTypeList.Contains(firstType));
        }

        private void addToList(Type firstType, Type secondType)
        {
            var matchingTypes = this.findListForType(firstType);
            if (!matchingTypes.Contains(secondType))
            {
                matchingTypes.Add(secondType);
            }
        }

        private void deleteFromList(Type firstType, Type secondType)
        {
            var matchingTypes = this.findListForType(firstType);
            if (matchingTypes.Contains(secondType))
            {
                matchingTypes.Remove(secondType);
            }
        }

        private List<Type> findListForType(Type type)
        {
            foreach (var keyValuePair in savedMatches)
            {
                if (keyValuePair.Key == type)
                {
                    return keyValuePair.Value;
                }
            }
            savedMatches.Add(type, new List<Type>());
            return findListForType(type);
        }
    }

该类的设计使得您提供哪种类型的参数无关紧要;它检查type1.list是否有type2,type2.list是否有类型。

一个简单的例子:

        typeManager.AddMatch(a, b);
        Console.WriteLine(typeManager.CanMatch(a, b)); // True
        typeManager.DeleteMatch(b, a);
        Console.WriteLine(typeManager.CanMatch(a, b)); // False
        Console.WriteLine(typeManager.CanMatch(a, c)); // False
        typeManager.AddMatch(a, c);
        Console.WriteLine(typeManager.CanMatch(a, c)); // True
        Console.WriteLine(typeManager.CanMatch(a, d)); // False
        typeManager.AddMatch(b, d);
        Console.WriteLine(typeManager.CanMatch(a, d)); // False
        Console.WriteLine(typeManager.CanMatch(d, b)); // True
        typeManager.DeleteMatch(d, b);
        Console.WriteLine(typeManager.CanMatch(d, b)); // False
        Console.WriteLine(typeManager.CanMatch(b, d)); // False