简体   繁体   English

如何在工厂方法中初始化具有多个参数的构造函数的类

[英]How to initialize the classes in factory method which have constructors with multiple parameters

Lets say I have a Shape interface which calculates the area of shape.假设我有一个计算形状面积的形状界面。 I add 2 implementations Rectangle and Square.我添加了 2 个实现 Rectangle 和 Square。 The challenge I see is both implementations have their own multiple argument constructors.我看到的挑战是两种实现都有自己的多参数构造函数。 How do I initialize them using a factory pattern.如何使用工厂模式初始化它们。 I wanted to solve it using java.我想用 java 来解决它。

public class Rectangle implements Shape {
int length;
int breadth;

public Rectangle(List<String> parameters) {
    this.length = Integer.parseInt(parameters.get(0));
    this.breadth = Integer.parseInt(parameters.get(1));
}

@Override
public int area() {
    return length * breadth;
}

} }

public class Square implements Shape {
int edge;

public Square(List<String> parameters) {
    this.edge = Integer.parseInt(parameters.get(0));
}

@Override
public int area() {

    return edge * edge;
}

} }

public interface Shape {
int area();

} }

public interface ShapeFactory {
public Shape make(String shapeType);
public List<String> getParameters(String shapeType);

} }

public class ShapeFactoryImpl implements ShapeFactory {
Map<String, List<String>> shapeInitMap = new HashMap<>();

public void init(){
    shapeInitMap.put("Circle", Arrays.asList(new String[]{"4"}));
    shapeInitMap.put("Rectangle", Arrays.asList(new String[]{"2","3"}));
}

@Override
public Shape make(String shapeType) {
    switch (shapeType) {
    case "Circle":
        return new Square(getParameters(shapeType));
    case "Square":
        return new Rectangle(getParameters(shapeType));
    default:
        break;
    }
    return null;
}

@Override
public List<String> getParameters(String shapeType) {

    return shapeInitMap.get(shapeType);
}

} }

Your solution is not optimal, because: 1) you have to create dedicated constructors for your concrete Shape s and you loose the type check (at compile time) of the parameters.您的解决方案不是最佳的,因为:1)您必须为具体的Shape创建专用的构造函数,并且您松散了参数的类型检查(在编译时)。 2) The init method of the concrete factory is error prone. 2)具体工厂的init方法容易出错。

Here's what I would do.这就是我要做的。 The concrete factory should carry the parameters of the concrete Shape s constructors, but not as indetermined strings (if you get strings from user input, convert them before the creation of the concrete factory):具体工厂应该携带具体Shape的构造函数的参数,但不能作为不确定的字符串(如果您从用户输入中获取字符串,请在创建具体工厂之前对其进行转换):

public interface ShapeFactory {
    public Shape make(String shapeType);
}

public class ShapeFactoryImpl implements ShapeFactory {
    private int circleRadius;
    private int rectangleLength;
    private int rectangleBreadth;

    public ShapeFactoryImpl(int circleRadius, int rectangleLength, int rectangleBreadth){
        this.circleRadius = circleRadius;
        this.rectangleLength = rectangleLength;
        this.rectangleBreadth = rectangleBreadth;
    }

    public Shape make(String shapeType) {
        switch (shapeType) {
            case "Circle": return new Circle(this.circleRadius); 
            case "Rectangle": return new Rectangle(this.rectangleLength, this.rectangleBreadth);
            default: throw new Exception("..."); 
        }
    }
}

The client does not need to know the concrete ShapeFactory he is using, nor has to worry about the concrete Shape he gets.客户端不需要知道他正在使用的具体ShapeFactory ,也不必担心他得到的具体Shape The dependency is inverted: abstractions, not details, play the key role.依赖关系是倒置的:抽象而不是细节起关键作用。 But if the number of possible shapes increases, you'll get a constructor with a lot of similar parameters.但是如果可能的形状数量增加,你会得到一个带有很多类似参数的构造函数。 Here's another solution:这是另一个解决方案:

public class ShapeFactoryImpl implements ShapeFactory {
    private Shape circle;
    private Shape rectangle;

    public ShapeFactoryImpl(Circle circle, Rectangle rectangle){
        this.circle = circle;
        this.rectangle = rectangle;
    }

    public Shape make(String shapeType) {
        switch (shapeType) {
            case "Circle": return this.circle.clone(); 
            case "Rectangle": return this.rectangle.clone();
            default: throw new Exception("..."); 
        }
    }
}

This is better, because you won't mix parameters: each concrete Shape contains its own parameters.这更好,因为您不会混合参数:每个具体的Shape都包含自己的参数。 If you want to make it more flexible, you can use a Map to move the reponsibility for the switch out of the concrete factory:如果你想让它更灵活,你可以使用 Map 将开关的责任移出混凝土工厂:

public class ShapeFactoryImpl implements ShapeFactory {
    private Map<String, Shape> shapeByType;

    public ShapeFactoryImpl(Map<String, Shape> shapeByType){
        this.shapeByType = shapeByType;
    }

    public Shape make(String shapeType) {
        Shape shape = this.shapeByType.get(Type).clone();
        if (shape == null) {
            throw new Exception("...");
        }
        return shape;
    }
}

I would even use an enum for shape types instead of a string, and an EnumMap to handle the switch:我什至会为形状类型使用enum而不是字符串,并使用EnumMap来处理开关:

public class ShapeFactoryImpl implements ShapeFactory {
    private EnumMap<ShapeType, Shape> shapeByType;

    public ShapeFactoryImpl(Map<ShapeType, Shape> shapeByType){
        this.shapeByType = shapeByType;
    }

    public Shape make(ShapeType shapeType) {
        return this.shapeByType.get(Type).clone();
    }
}

The client has to know the Shape and ShapeFactory interface and the ShapeType enum.客户端必须知道ShapeShapeFactory接口以及ShapeType枚举。 The "server" provides the concrete ShapeFactoryImpl instance. “服务器”提供具体的ShapeFactoryImpl实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM