首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对于你的模型来说,实现一个行为(接口)是不是不好的设计?

对于你的模型来说,实现一个行为(接口)是不是不好的设计?
EN

Stack Overflow用户
提问于 2014-02-24 11:40:22
回答 3查看 111关注 0票数 3

如果我的问题真的很琐碎的话,很抱歉。但是我觉得我不擅长‘设计’,所以想要对这个话题有一些见解。

假设我有一个空接口果树,有不同的java实现,比如Apple、Mango、Orange等等。

我有一台FruitBasket,里面有各种水果的开胃机。

代码语言:javascript
复制
basket.setApple(Apple a);
basket.setOrange(Orange o);

诸若此类。

现在,当我需要为篮子设置一个特定的水果时,我需要调用正确的设置器。其中一种方法是拥有一个Utility,它将遍历所有te模型对象(成果),并调用篮子上相应的setter。

就像这样。

代码语言:javascript
复制
public class FruitUtilty
{

 public static void setAllFruits(FruitBasket basket, List<Fruits> fruits)
  {
    for(Fruit fruit : fruits)
     {
        if(fruit.getClass() == Apple.class)
        {
            basket.setApple((Apple)fruit);
        }
        else if(fruit.getClass() == Mango.class)
        {
            basket.setMango((Mango)fruit);
        }
        else if(fruit.getClass() == Orange.class)
        {
            basket.setOrange((Orange)fruit);
        }

     }
  }

}

但我在这里看到的问题是丑陋的如果/否则的梯子。每次添加模型对象时,都必须修改该实用程序。

因此,我提出了一个设计,其中接口不会是空的,而是对所有要实现的结果具有“setBasket”行为。即

代码语言:javascript
复制
public interface Fruit
{
   public void setBasket(FruitBasket b);
}

现在,所有的成果(应该是哑模型对象)都在这个way.For中实现了这个接口。苹果会是这样的

代码语言:javascript
复制
public class Apple implements Fruit {
 ....
 ....
 ....
 public void setBasket(FruitBasket b) {
   b.setApple(this);
 }
}

现在,我们不再需要FruitUtility类了,无论在什么地方调用了结果实用程序的setAllFruits,我们都可以像这样使用代码片段

代码语言:javascript
复制
FruitBasket f =  new FruitBasket();
List<Fruit> fruits = getAllFruits();

for(Fruit fruit: fruits)
 {
     fruit.setBasket(f);
 }
 ........
 ........

我的团队负责人说,这是一个非常糟糕的设计,因为我已经“稀释”了模型对象。我们的模型应该是一个“哑巴”对象,只能携带数据。因此,我们应该坚持以实用程序为基础的方法,或者除了这个方法以外的任何其他方法。

做事情的正确/最好的方法是什么(至少在JAVA中)?

提前谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-02-24 12:09:19

我认为在这种情况下水果应该是“哑巴”。今天你把它们加到篮子里,明天你会在商店里把它们卖出去,一周后你会把它们混合成沙拉:)

如果将一个'setBasket‘方法添加到水果接口中,那么这两个概念就会在接口级别上耦合起来,这是不好的。另一方面,如果不是可扩展的,正如您已经说明过的那样。

我认为最好的方法(至少这就是我解决这个问题的方法)是引入另一个抽象,比如" action“,它表示可以对结果执行的操作。

如果我们谈论的是篮子,我认为您可以创建一个公共接口,并为每种水果实现它。

示例:

代码语言:javascript
复制
public interface FruitBasketAdder {

     void addFruit(Fruit fruit, Basket basket);
}


public class AppleBasketAdder implements FruitBasketAdder {

     public void addFruit(Fruit fruit, Basket basket) {

          Apple apple = (Apple) fruit;
          basket.addApple(apple);
          ....
     }
}

public class OrangeBasketAdder implements FruitBasketAdder {
     public void addFruit(Fruit fruit, Basket) {

          Orange orange = (Orange) fruit;
          basket.addOrange(orange);
          ....
     }

}

现在,您可以生成一个注册表,它表示可以处理各种水果的策略。如下所示:

代码语言:javascript
复制
Map<Class<Fruit>>, FruitBasketAdder> registry = new HashMap<>();
registry.put(Orange.class, new OrangeBasketAdder());
registry.put(Apple.class, new AppleBasketAdder());
.....

最后一点是使用这个注册表。比方说,您有一个常用的方法,它接受一个“水果”列表作为参数,并尝试将其添加到篮子中,就像您在示例中用"if“表示的那样。因此,您应该从注册表中找到指定的" BasketAdder“(假设您可以访问对注册表的引用),并通过调用相关的BasketAdder将水果添加到篮子中。给你:

代码语言:javascript
复制
public void addFruitsToTheBasket(List<Fruit> fruits, Basket basket) {

    for(Fruit fruit : fruits) {

        BasketAdder adder = registry.get(fruit.getClass());
        adder.addFruit(fruit, basket);

    }
}

这个设计比"if“要好得多,因为它允许在不破坏接口的情况下动态添加新的水果。只需创建一个BasketAdder,将其传递到注册表,您就完成了,主要算法(遍历+添加到篮)保持不变。

标记

希望这能有所帮助

票数 3
EN

Stack Overflow用户

发布于 2014-02-24 11:49:13

我认为你的团队领导提出了一个正确的观点。您正在将功能从FruitBasket转移到Fruit,但是Fruit甚至不应该了解FruitBasket。如果您有一个FruitBag和一个FruitBox,会发生什么呢?无论何时引入这样的类,您都必须更改每个Fruit实现者。

使用正确的setter函数的逻辑是FruitBasked内部的,应该保持不变。

关于“最好的方法”。在这里我没有想到最好的解决办法。水果种类之间的区别必须在某个地方进行。if .. else可能不是最漂亮的解决方案,但看起来不错。不过,使用enumswitch/case可能更好。这样,当您忘记一种类型时,就会得到编译器的警告。

通常情况下,整个setApplesetOrange方法是问题的根源。这样就不需要苹果和橘子来实现Fruit了。但是,要想摆脱这种局面,通常是不容易的。它总是取决于细节。

票数 1
EN

Stack Overflow用户

发布于 2014-02-24 11:47:04

这取决于周围的工具链和/或开发风格,如果您有一个愚蠢的数据结构“模型”或一个实现业务逻辑--在这两个极端之间有许多不同之处,那么这个问题通常是无法回答的。但是实用程序类方法有一个主要的缺点,那就是关注点的分离,因为查看水果篮类,没有人知道水果分离是如何实现的,而不检查哪些类访问水果篮,这样在最坏的情况下,有人在其他地方实现相同的算法,因为他不知道这一个实用程序类。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21986694

复制
相关文章

相似问题

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