首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何正确地使用接口进行解耦

如何正确地使用接口进行解耦
EN

Software Engineering用户
提问于 2019-11-15 14:12:31
回答 1查看 163关注 0票数 3

我有一个生态系统模拟,动物相互移动和碰撞。下面是我处理碰撞的方法:

代码语言:javascript
复制
public void HandleCollisionBetween(Animal a, Animal b)
    {
        if (a.GetType().Name == b.GetType().Name) { // same type collision
            bool fishCollision = a.GetType().Name == typeof(Fish).Name;
            if (fishCollision) {
                AddAnimal(new Fish());
            }
        }
        else { // bear-fish collision
            Bear bear = a.GetType() == typeof(Bear) ? a as Bear : b as Bear;
            Fish fish = a.GetType() == typeof(Fish) ? a as Fish : b as Fish;

            bear.Eat(fish);
            RemoveAnimal(fish);
        }
    }

这段代码是我生态系统类的一部分。有人建议我将这段代码作为一个单独的类,实现一个接口,然后使用它。这样它就可以测试了。问题是:当两种动物发生碰撞时,我需要添加或移除生态系统中的动物。我所能想到的就是:

代码语言:javascript
复制
interface ICollisionHandler {
    void HandleCollisionBetween(Animal a, Animal b, Ecosystem ecosystem);
}

但是这个关于生态系统的说法是不对的。我非常感谢任何能帮助我改进这类事情的帮助和信息。

EN

回答 1

Software Engineering用户

回答已采纳

发布于 2019-11-15 16:09:23

所以一开始,我发现当你交叉比较很多类的时候,一种方法是备份并问问自己,你写的类是否应该重新组合成数据,而不是类,至少在你的应用程序中它们相交的接触点是这样的。因此,首先,我将给出一个示例,将熊/鱼类缩减为一个基类,动物,并将熊或fosh的详细信息打包为数据。但是,您可以进一步研究这个示例,并拥有一个从purpose继承的熊和鱼类,但是为了确定碰撞结果,我不认为将它们作为类增加太多的价值。这是我的积木。

  • 一个EcoSystem类,它知道环境中存在哪些动物,并且在需要碰撞时具有可调用的公共功能。
  • 一个允许实例理解其物种(熊或鱼)的动物基类,以及帮助在生态系统中跟踪它们的唯一标识符。
  • 唯一需要更改的CollisionResolver类是处理映射新的动物冲突,如果/何时添加新的动物类型。

我并不是什么都相信接口的人,但我将给出这个例子,它将问题分解为上面的几个部分:

代码语言:javascript
复制
public class Animal
{
    public string Identifier { get; } 
    public string SpeciesName { get; } 

    public Animal(string animalName)
    {
        SpeciesName = animalName;
        Identifier = Guid.NewGuid().ToString();
    }
}

public class AnimalCollisionResolver
{
    public ICollisionResult ResolveCollision(Animal a, Animal b)
    {
        // Handle the easy case -> reproduction of same species
        if (a.SpeciesName == b.SpeciesName)
            return new AddNewAnimalCollisionResult { NewAnimalToAdd = new Animal(a.SpeciesName) };

        // Handle handle harder case, how to determine which ones eat the others, this will be as complex as you need it

        var animals = new[] { a, b };
        var names = animals.Select(_ => _.SpeciesName);

        // Bear-eats-Fish mapping here
        if (names.Contains("Bear") && names.Contains("Fish"))
        {
            return new RemoveSpecificAnimalCollisionResult
            {
                IdentifierOfAnimalToRemove = animals.Single(_ => _.SpeciesName == "Fish").Identifier
            };
        }

        throw new NotImplementedException("I need to map out the rest of the collision resolutions here.");
    }
}

// This could be an abstract base class and the code would not change, FYI
public interface ICollisionResult { }

public class AddNewAnimalCollisionResult : ICollisionResult
{
    public Animal NewAnimalToAdd { get; set; }
}

public class RemoveSpecificAnimalCollisionResult : ICollisionResult
{
    public string IdentifierOfAnimalToRemove { get; set; }
}

public class Ecosystem
{
    public List<Animal> CurrentAnimals { get; set; }

    public AnimalCollisionResolver CollisionResolver { get; set; }

    public Ecosystem()
    {
        // seed the ecosystem here
        CurrentAnimals = new List<Animal> {
            new Animal("Bear"),
            new Animal("Bear"),
            new Animal("Fish"),
            new Animal("Fish"),
        };

        CollisionResolver = new AnimalCollisionResolver();
    }

    public void HandleCollision(Animal a, Animal b)
    {
        var result = CollisionResolver.ResolveCollision(a, b);

        if (result is AddNewAnimalCollisionResult)
        {
            var addResult = (AddNewAnimalCollisionResult)result;
            CurrentAnimals.Add(addResult.NewAnimalToAdd);
        }

        else if (result is RemoveSpecificAnimalCollisionResult)
        {
            var removeResult = (RemoveSpecificAnimalCollisionResult)result;
            CurrentAnimals = CurrentAnimals.Where(_ => _.Identifier != removeResult.IdentifierOfAnimalToRemove).ToList();
        }

        else
        {
            throw new Exception("Unknown ICollisionResult here");
        }

        PrintOutTheCurrentAnimals();
    }

    public void PrintOutTheCurrentAnimals()
    {
        foreach (var animal in CurrentAnimals)
            Console.WriteLine($"{animal.SpeciesName} {animal.Identifier}");
        Console.WriteLine("");
    }
}

我不知道你是如何声明这些动物的,并决定谁与谁发生碰撞,但这里有一个例子来展示这些基本知识:

代码语言:javascript
复制
var ecoSystem = new Ecosystem();
ecoSystem.PrintOutTheCurrentAnimals();

var allBears = ecoSystem.CurrentAnimals.Where(_ => _.SpeciesName == "Bear");
var bear1 = allBears.Take(1).Single();
var bear2 = allBears.Skip(1).Take(1).Single();
var fish1 = ecoSystem.CurrentAnimals.First(_ => _.SpeciesName == "Fish");

ecoSystem.HandleCollision(bear1, fish1);

ecoSystem.HandleCollision(bear1, bear2);
票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/401131

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档