代码之家  ›  专栏  ›  技术社区  ›  akaihola dnlcrl

面向对象设计访谈[结束]

oop
  •  9
  • akaihola dnlcrl  · 技术社区  · 5 年前

    this 问题

    11 回复  |  直到 12 年前
        1
  •  13
  •   JeremyDWill    15 年前

    好的,我想到了一个很好的方法——利用OOP覆盖、子类和超类:

    namespace Animals{
    
        // base class Animal
        class Animal{
    
         public void eat(Food f){
    
         }
    
        }
    
    
        class Carnivore extends Animal{
    
          public void eat(Meat f){
    
          }
    
        }
    
        class Herbivore extends Animal{
    
          public void eat(Plant f){
    
          }
    
        }
    
        class Omnivore extends Animal{
    
          public void eat(Food f){
    
          }
        }
    
    }
    
    namespace Food{
    
        // base class Food
        class Food{
    
        }
    
        class Meat extends Food{
    
        }
    
        class Plant extends Food{
    
        }
    
    }
    

    eat 方法与它实际可以吃的食物类型有关。

    因此:

    Plant grass = new Plant();
    Herbivore deer = new Herbivore();
    deer.eat(grass); // ok
    
    Plant grass2 = new Plant();
    Carnivore tiger = new Carnivore();
    tiger.eat(grass2); // not ok.
    
    Meat deer2 = new Meat();
    tiger.eat(deer2); // ok
    

    最后一个问题是,当你指定 deer 是一个 Herbivore ,你不能让它成为一个 Meat tiger 吃。然而,在一天结束时,这应该足以解决面试问题,同时又不会让面试官睡着。

        2
  •  8
  •   Gareth    15 年前

    有一张很棒的海报 Liskov Substitution Principle 也就是说,“如果它看起来像鸭子,像鸭子一样呱呱叫,但需要电池,那么你可能得到了错误的抽象。”这是一个快速的答案——一些对象可以是动物和食物,因此除非你愿意走多重继承的路径,否则分类模式是完全错误的。

    一旦你越过了这个障碍,剩下的就没有尽头了,你可以引入其他的设计原则。例如,您可以添加一个允许使用对象的可编辑接口。您可以使用面向方面的方法,并为食肉动物和草食动物添加装饰器,这将只允许使用正确的对象类。

    关键是要能够独立思考,能够看到和解释问题的各个方面,并且能够很好地沟通。也许

        3
  •  6
  •   hasen    15 年前

    我会叫他把它抓起来。这是一个可怕的抽象概念。更不用说我们没有任何背景。抽象不是凭空而来,也不是凭空而来的“正确”的“想法”。告诉我你首先要解决什么问题,这样我们就可以评估这个抽象。

    制造 Eatable 接口(或者您可以调用它 Food ,如果你愿意的话),因为我们没有上下文,所以我假设这是一个玩具控制台程序,它只打印:

    <X> ate <Y>
    

    因此,这个接口只需要一个 getFoodName() 方法。

    isXFoodType 比如,, isGrassFoodType() , isMeatFoodType() 等等 Cow Eat(Eatable e) 我会检查一下 isGrassFoodType() ,失败时,打印:

    "Cow can't eat " + e.getFoodName()
    
        4
  •  4
  •   Ken    15 年前

    艾伦·凯(Alan Kay)创造了“面向对象编程”这一术语,他说“OOP对我来说只意味着消息传递、本地保留、保护和隐藏状态进程,以及所有事物的极端后期绑定”。

    在我看来,试图解决数据模型中的这个“问题”听起来像是后期绑定的反面:为什么需要编译器来强制执行这个问题?我根本不担心改变模型。如果你通过了一些你不能吃的东西,你会抛出一个例外——就像在现实生活中一样,差不多!

        5
  •  3
  •   Dr. Xray    15 年前

    抽象动物类应该有以食物为参数的吃法。

    例如,对于食肉动物:

     private void eat(Food food)
     {
          if(food instanceof Animal)
          {
               happilyEat();
          }
          else
          {
               sniff&TurnAway();
          }
     }
    

    问题解决了。

        6
  •  2
  •   andreialecu    14 年前

    在C#顺便说一句,使用泛型很容易:

    public class Food
    {
    }
    
    public abstract class Animal<T> : Meat where T:Food
    {
        public abstract void Eat(T food);
    }
    
    public class Herbivore : Animal<Plant>
    {
        public override void Eat(Plant food)
        {
            Console.WriteLine("Herbivore eats plants.");
        }
    }
    
    public class Omnivore : Animal<Food>
    {
        public override void Eat(Food food)
        {
            Console.WriteLine("Omnivore eats food.");
        }
    }
    
    public class Carnivore : Animal<Meat>
    {
        public override void Eat(Meat food)
        {
            Console.WriteLine("Carnivore eats meat.");
        }
    }
    
    public class Plant : Food
    {
    }
    
    public class Meat : Food
    {
    }
    
    public class Cow : Herbivore
    {
    }
    
    public class Tiger : Carnivore
    {
    }
    
    public class Human : Omnivore
    {
    }
    

    用法:

       var human = new Human();
       var tiger = new Tiger();
       var cow = new Cow();
       var plant = new Plant();
    
       human.Eat(cow);
       tiger.Eat(human);
    
       cow.Eat(tiger); // this doesn't compile
       tiger.Eat(plant); // neither does this
    
        7
  •  1
  •   Chip Uni    15 年前

    我同意赛昂猫的观点:如果没有多重继承(即使是类似Java的接口),这种抽象也无法很好地工作

    动物:

    • 食肉动物
    • 食草动物

    食物:

    • 蔬菜

        8
  •  1
  •   Jim Ferrans    15 年前

    任何动物都是食物,任何蔬菜都是食物。事实上,老虎可以被牛吃掉(朊病毒病是通过将受感染的绵羊神经组织喂给未受感染的绵羊而传播的。)

    你可以有一个物种的等级,阿拉 Linnaeus List<Species> 这记录了它的典型饮食。完全抛弃食物等级制度,它只会混淆事物。

    而且,如果你唯一的问题是记录每个物种的饮食,那么多物种类是不必要的。只需使用一个物种名称作为一个实例变量和 列表<物种>

        9
  •  0
  •   Dean J    15 年前

    没有最好的解决办法。你可能想让它成为一个社区维基,因为这是主观问题的公认做法。

    我会考虑到底是什么使层次结构成为最好的父类,并试图找出“最佳”在该上下文中的含义。

    所有东西都有可能具有名称属性。但在某种程度上,那里的一切都是食物;如果它能吃东西,有东西能吃。我可以将Food作为父类,并为其提供一个返回布尔值的方法,以检查参数对象是否可以吃当前对象。

    class Food {
        boolean canBeEatenBy(Food hungryObject)
        String name
    }
    

    这似乎是最简单的类层次结构,可以满足我第一次使用时可能需要的所有内容?

    也就是说,大多数面试问题中最重要的部分是你对面试者的感受,而不是他们给出的确切答案。

        10
  •  0
  •   RichN    15 年前

    Double dispatch ,也许吧?

        11
  •  0
  •   Shane    15 年前

    如果你认为这个系统会变得非常庞大,我建议将植物/肉类和食草动物/食肉动物/杂食动物分类。

    确保系统对所有植物/动物都有一个名为getFoodName()和getFoodType()的标准接口,您可以通过为植物/动物创建一个名为species的父类来强制执行该接口。

    我看到的植物/肉和食肉动物/草食动物亚类的问题是,猫鼬是食肉动物,但它可能不能吃犀牛(可能有更好的例子),因此除了“我吃肉,你吃植物”之外,还需要一些限制。

    如果它不会变得难以置信的大,而你又想变得神经质,你可以为每一个动物亚类存储允许食物的静态枚举。所以老虎可以储存鹿、羚羊等。