首页
学习
活动
专区
圈层
工具
发布

蔬菜厂
EN

Code Review用户
提问于 2012-01-30 20:54:21
回答 4查看 1.4K关注 0票数 10

我对Java很陌生。我正在尝试构建一个简单的类层次结构。

代码语言:javascript
复制
abstract class Vegetable
{
    public Vegetable(double weight)
    {
        this.weight = weight;
        ...
    }

    ...
}

class Tomato extends Vegetable
{
    public Tomato(double weight)
    {
            super(weight);
        ...

    }
    ...
}

class Cucumber extends Vegetable
{
    public Cucumber(double weight)
    {
            super(weight);
        ...

    }
    ...
}

我在类Vegetable中有一些抽象方法,它们在TomatoCucumber中被重写。我想实施买蔬菜的逻辑。我为它创建了以下类:

代码语言:javascript
复制
public class VegetableFactory
{
    public static ArrayList<Vegetable> buy(int num, Class vegetableClass)
    {
        ArrayList<Vegetable> res = new ArrayList<Vegetable>(num);
        for (int i = 0; i < num; i++)
        {
            double weight = (Math.random() * 200) + 100;
            Vegetable v = null;
            try
            {
                v = (Vegetable) vegetableClass.getDeclaredConstructor(Double.TYPE).newInstance(weight);
            } catch (InstantiationException e)
            {
                e.printStackTrace();
            } catch (IllegalAccessException e)
            {
                e.printStackTrace();
            } catch (InvocationTargetException e)
            {
                e.printStackTrace();
            } catch (NoSuchMethodException e)
            {
                e.printStackTrace();
            }
            res.add(v);
        }
        return res;
    }
}  

这样做好吗?把它命名为工厂在意识形态上是正确的吗?任何改进建议都将受到高度赞赏。

EN

回答 4

Code Review用户

回答已采纳

发布于 2012-01-31 01:07:32

我会使用枚举类型,而不是必须传递一个类。这样,就不可能传递一些不好的内容,而且您可以在编译时而不是运行时捕获错误。

代码语言:javascript
复制
enum VegetableType { CARROT, TOMATO, CUCUMBER };

那么你的购买方法就会很简单

代码语言:javascript
复制
static ArrayList<Vegetable> buy(int num, VegetableType vegType) {
    ArrayList<Vegetable> veggies = new ArrayList<Vegetable>(n); //n is the initial capacity - size is still zero.
    for(int i=0; i < num; ++i) {
        double weight = (Math.random() * 200) + 100;

        switch(vegType) {
        case VegetableType.CARROT:
            veggies.add(new Carrot(weight));
            break;
        case VegetableType.TOMATO:
            veggies.add(new Tomato(weight));
            break;
        case VegetableType.CUCMBER:
            veggies.add(new Cucumber(weight));
            break;
        }
    }
    return veggies;
 }

当然,现在的问题是在循环的中间有一个大的switch语句。一般来说,虽然很难看,但我认为这就足够了--您可以对每个单独的构造函数进行更多的控制,因此您不会被限制在相同的参数集上。

您可以做的另一件事是在VegetableType上使用一个工厂方法来创建一个实例:

代码语言:javascript
复制
enum VegetableType {
    CARROT { Vegetable createInstance(int weight) { return new Carrot(weight); }},
    TOMATO { Vegetable createInstance(int weight) { return new Tomato(weight); } },
    CUCUMBER { Vegetable createInstance(int weight) { return new Cucumber(weight); } };

    abstract Vegetable createInstance(int weight);
}

然后你的名单就变成

代码语言:javascript
复制
static ArrayList<Vegetable> buy(int num, VegetableType vegType) {
    ArrayList<Vegetable> veggies = new ArrayList<Vegetable>();
    for(int i=0; i < num; ++i) {
        double weight = (Math.random() * 200) + 100;
        veggies.add(vegType.createInstance(weight));
    }
    return veggies;
 } 

最后,如果您想变得更漂亮,java.lang.reflectConstructor类:

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/reflect/Constructor.html

然后,您可以使用它将构造函数获取到您选择的Vegetable类型,然后在循环中反复调用构造。

票数 14
EN

Code Review用户

发布于 2012-01-31 04:46:34

这样做好吗?

不是的。对每个类的关注点分离给予更多的思考。购买逻辑不属于工厂。工厂只用于创建各种素食类型。Buy应该在VegetableStand类中,或者可能在Vegetable类中。

如果“购买”逻辑在每个蔬菜中都是唯一的,那么将buy()放在Vegetable类中--特别是如果它还具有一个price属性。即使如此,我仍然可以看到一个VegetableCart.Buy(),它将所有的东西积累到一个“袋子”中,这样就可以添加不同的蔬菜、数量和价格--给客户一个总价。

把它命名为工厂在意识形态上是正确的吗?

不是你写的那样。素食工厂是用来制造各种蔬菜的。我希望看到一个create()方法,如上面所建议的那样传递一个枚举。

代码语言:javascript
复制
public class VegetableStand {
    VeggieFactory myVF = new VeggieFactory();

    public ArrayList<Vegetable> bag = new ArrayList<Vegetable>;

    public ArrayList<Vegetable> Buy (VegetableType whatKind ,int howMany){
        for (int i=0, i<howMany; i++) {
            bag.add(myVF.Create(whatKind);
        }
    }

    public double TotalSale (ArrayList<Vegetable> bag) {
        double totalPrice = new double;

        foreach (Vegetable item in Bag) {
             totalPrice += item.Price;
         }

       return totalPrice;
    }
}

internal class VeggieFactory {
    public static Vegetable Create(VegetableType whatKind) {
        Vegetable thisKind;

        switch(whatKind) {
            case: VegetableType.carrot
                thisKind = CreateCarrot();
                break;
            case: VegetableType.cucumber
                thisKind = CreateCucumber();
                break;
            default:
               throw new Veggie not invented yet exception;
        }
        return thisKind;
    }
}

然后,在buy()方法中,在for循环中不应该有一个大的switch语句。如果你通过一个素食主义的例子,这是没有道理的。如果你已经创造了那个素食主义者,那为什么是工厂?

  • 您应该将ArrayList<Vegetable>的创建与蔬菜本身的创建分开。buy()方法为您购买的每一个蔬菜创建一个新列表。而且,您可能需要实例化一个素食者w/o列表。
票数 6
EN

Code Review用户

发布于 2012-01-31 12:17:35

据我所见,还没有人指出列表的引用类型应该仅为List。而不是

代码语言:javascript
复制
ArrayList<Vegetable> res = new ArrayList<Vegetable>(num);

使用

代码语言:javascript
复制
List<Vegetable> res = new ArrayList<Vegetable>(num);

该方法的签字也应改变:

代码语言:javascript
复制
public static List<Vegetable> buy(int num, Class vegetableClass)

在Java中类型列表与类型数组列表

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

https://codereview.stackexchange.com/questions/8467

复制
相关文章

相似问题

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