我正在尝试用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);
}
}
任何想法如何克服这个问题?我不得在工厂内收到用户的意见(必须从外面收到)。
谢谢!
答案 0 :(得分:30)
您有两种选择:
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)
您的所有实现必须使用相同数量的参数,您有三个选项:
答案 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);
}
}
如果形状参数之间有任何共同参数,您可以使用继承来更好地管理它