1

我正在编写一个归档系统,如下所示:

IAchievement - 所有成就必须实现的接口

AchievementManager - 使用用户 ID 检查所有成就的类

我的想法是在 ArchivementManager 上有一个共享功能,因为我可以执行类似的操作

AchievementManager.checkUser(userId)

或者

AchievementManager.check(userId, achievementId)

无论如何,AchievementManager 应该为每个 IAchievement 实现调用一个函数检查。

因为我检查的每个成就都有一个实例没有任何意义,所以我希望能够将检查方法声明为共享/静态。所以在AchievementManager里面我可以调用

AchivementXXX.check(userId)

但是我不能在我的界面中声明共享函数。

有什么解决方法吗?实施成就系统是一种糟糕的方法吗?

编辑:

这不是游戏,而是 ASP.NET 中的网站

4

5 回答 5

1

如果您的方法是定义一个接口,那么让AchievementManager 持有每个相关成就类型的实例是有意义的。

这也是有道理的,因为人们会期望成就实例需要存在,例如为了跟踪各种游戏状态和监听各种游戏事件,以便他们可以检测到成就已经实现。否则,成就将如何实现他们的 Check 方法?

于 2012-12-18T08:37:06.957 回答
0

您可以在超类成就中实现您的接口,然后将该类声明为 MustInherit。所以每个成就都继承自超类,并且可以覆盖独特的部分。您的检查方法可以设置为不可覆盖,这样没有人可以修改它

于 2012-12-18T08:41:52.340 回答
0

因此,从评论开始,您在这里有一些选择..

public class AchievementA : AchievementBase
{
  public void GetAchievementForAByUser(int userId)
  {
       base.CheckId(userId);
  }



 }

public class AchievementB : AchievementBase
 {

  }

 public class AchievementManager : IAchievement
{
    protected void CheckId(int userId)
{

}

}

您的接口 IAchievement 将实现可用于每个成就子类的方法协定。

于 2012-12-18T08:46:18.253 回答
0

还有一种不使用接口和继承的方法:

class Achievement {
    private Predicate<UserId> actualCheckUser;

    public bool CheckUser(UserID userId) {
        return actualCheckUser(userId);
    }

    public Achievement(Predicate<UserId> checkUser) {
        if (checkUser == null) {
            throw new ArgumentNullException("checkUser");
        }
        actualCheckUser = checkUser;
    }
}

您调用成就的方法来检查用户是否拥有它。如果将成就表示为类型,那么成就的方法就是类型的方法,也就是静态方法。但是你不能在接口中有静态方法。如果您将成就表示为对象,那么成就的方法就是一个普通的旧对象的方法。

但是您必须使此方法在成就类的不同实例中表现不同。做到这一点的一种方法确实是CheckUser抽象并覆盖它,但是您再次需要为每个成就声明一个单独的类。另一种方法是使用委托——你将它插入你的成就对象,就是这样。在引擎盖下,它也会导致创建一个额外的类。

就我个人而言,我不知道哪种设计更好,但我认为元编程在类型方面比在对象方面更难。

于 2012-12-18T08:58:59.553 回答
0

我知道这篇文章已经有将近一年的历史了,但是为什么不使用 DI 呢?例子:

interface IAchievement {
    void Check(User user);
}

class UserMade200PostsAchievement : IAchievement {

    void Apply(User user) {
            var postCount = _repo.AsQueryable<Post>().Count(x => x.CreatedByUserId == user.Id);
            if (postCount >= 200)
                //apply achievement, insert some data, whatever

    }

}

全部注册:

//Note this may not be the exact command, depends on your choice of IoC container
container.RegisterInterfaceImplementers(typeof(IAchievement));

public class AchievementManager {

    //All instances of IAchievement injected
    private IAchievement[] Achievements

    public AchivementManager(IAchievement[] achievements) {
        Achievements = achievements;
    }

    public void Check(User user) {
        foreach(var a in achivements)
            a.Apply(user);
    }

}

这样,当您添加新成就时,它会自动被拾取。

于 2013-11-13T15:24:54.763 回答