具体对象采用不同构造函数参数时的Java工厂

时间:2012-12-14 20:32:38

标签: java design-patterns factory

我正在尝试用Java实现Factory模式。 我有一个名为Shape的类,Circle和Triangle扩展。 问题是Shape构造函数只获得2个参数,而Circle获得3个参数,因此Triangle(我不会在代码部分显示,因为它与Circle相同)。 为了更好地展示它:

    private interface ShapeFactory{
        public Shape create(int x, int y);
    }

    private class CircleFactory implements ShapeFactory{
        public Shape create(float radius, int x, int y){ //error
            return new Circle(radius, x,y);
        }
    }

任何想法如何克服这个问题?我不得在工厂内收到用户的意见(必须从外面收到)。

谢谢!

5 个答案:

答案 0 :(得分:30)

您有两种选择:

1)Abstract Factory

RectangularShape extends Shape

RoundShape extends Shape

RectangularShapeFactory以及RoundShapeFactory

2)Builder(另见有效Java中的第2项)

public Shape {
    private final int x;
    private final int y;
    private final double radius;

    private Shape(Builder builder) {
        x = builder.x;
        y = builder.y;
        radius = builder.radius;
    }

    public static class Builder {
        private final int x;
        private final int y;
        private double radius;

        public Builder(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public Builder radius(double radius) {
            this.radius = radius;
            return this;
        }

        public Shape build() {
            return new Shape(this);
        }    
    }
}

//in client code 

    Shape rectangle = new Shape.Builder(x,y).build();
    Shape circle = new Shape.Builder(x,y).radius(radiusValue).build();

答案 1 :(得分:6)

你想要做的事情根本不可能。如果构造函数参数不同,那么客户端代码必须为Circle执行与Square不同的工作,并且您无法使用统一代码解决此问题。如果除了处理您认为应该在工厂中发生的构造函数参数之外,工厂还在进行其他工作,那么您需要将此问题发布到您的问题中,并说明您在分解此常见代码工作时遇到的困难。

答案 2 :(得分:5)

您的所有实现必须使用相同数量的参数,您有三个选项:

  • 让工厂存储附加参数,因此您只需要提供例如中心。
  • 让工厂接受所有论据,即使有些工厂可能会忽略其中的一些。
  • 的参数是可变长度。例如“双倍......”这个问题是调用者需要知道工厂需要什么才能破坏工厂的目的。 IMHO。

答案 3 :(得分:0)

具有Shape接口通常是一个糟糕的设计,因为它非常有限。您需要不同的信息来描述不同的形状。调整大小就是一个很好的例子。对于圆形,您需要更改半径,对于矩形,需要更改两侧,这意味着传递两个参数而不是一个。

您可以通过传递某种形状描述符(例如,实际形状必须适合的矩形)来克服此问题。因此,假设您所有的形状均已使用类进行了预定义并且您想对其进行缩放,则可以适当地调整其大小。如果要使用自定义形状,则必须以某种方式扩展形状描述符,以包含自定义形状所需的所有信息,但要与现有形状保持兼容。这不一定很困难,您可以添加可以为null的属性或参数。在这里,我仅添加新参数。

private interface ShapeFactory{
    public Shape create(float x, float y, float width, float height);
}

private class CircleFactory implements ShapeFactory{
    public Shape create(float x, float y, float width, float height){
        float radius = Math.min(width, height);
        return new Circle(radius, x, y);
    }
}

另一个人以为您通常以这种方式使用工厂(当然,鞋面也可以根据您的需求而定):

private interface ShapeFactory{
    public Shape create(float x, float y, float width, float height, bool isCircle);
}

private class MyShapeFactory implements ShapeFactory{
    public Shape create(float x, float y, float width, float height, bool isCircle){
        if (isCircle)
            return new Circle(Math.min(width, height), x, y);
        else
            return new Rectangle(width, height, x, y);
    }
}

因此,工厂不一定具有与构造函数相同的参数。许多人有这种印象,因为我想他们试图使工厂自动化并仅传递类列表,而没有有关如何实例化它们的任何信息。人们也经常通过自动DI容器提交错误。

在这里,真正重要的是高层代码是否想知道它返回哪种Shape实现。但是在某些情况下,您可能拥有或重构了某种通用描述符。例如,您不一定有一个Shape.scale(width, height)方法,如果是这样,您将无法调整圆形或矩形的大小,因为与构造函数一样,缩放比例在那里也有所不同。但是,如果您只想打电话给Shape.draw(canvas)之类的东西,那我想您很好。

与此同时,我发现了一个具有类似答案的类似问题,也许您也可以从中学到以下知识:https://softwareengineering.stackexchange.com/a/389507/65755

答案 4 :(得分:0)

您可以使用类来包装工厂参数,如下所示:

public interface ShapeArguments{
}

public class CircleArguments implements ShapeArguments{
 ...

 public CircleArguments(... radius,... x,... y){
    ...
 }
}

private interface ShapeFactory{
        public Shape create(ShapeArguments args);
    }

    private class CircleFactory implements ShapeFactory{
        public Shape create(ShapeArguments args){
            CircleArguments circleArgs = (CircleArguments)args;
            return new Circle(circleArgs.radius, circleArgs.x,circleArgs.y);
        }
    }

如果形状参数之间有任何共同参数,您可以使用继承来更好地管理它