Как инициализировать классы в методе фабрики, которые имеют конструкторы с несколькими параметрами - PullRequest
1 голос
/ 20 сентября 2019

Допустим, у меня есть интерфейс Shape, который вычисляет площадь формы.Я добавляю 2 реализации Rectangle и Square.Проблема, которую я вижу, состоит в том, что обе реализации имеют свои собственные конструкторы с несколькими аргументами.Как мне их инициализировать с помощью заводского шаблона.Я хотел решить это с помощью 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);
}

}

1 Ответ

0 голосов
/ 23 сентября 2019

Ваше решение не является оптимальным, потому что: 1) вам нужно создать специальные конструкторы для ваших конкретных Shape s, и вы потеряете проверку типа (во время компиляции) параметров.2) Метод init конкретного завода подвержен ошибкам.

Вот что я бы сделал.Бетонный завод должен нести параметры конкретных Shape s конструкторов, но не как неопределенные строки (если вы получаете строки из пользовательского ввода, преобразуйте их до создания конкретного завода):

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("..."); 
        }
    }
}

Клиент не должен знать конкретный ShapeFactory, который он использует, и не должен беспокоиться о конкретном Shape, который он получает.Зависимость инвертирована: ключевую роль играют абстракции, а не детали.Но если количество возможных фигур увеличится, вы получите конструктор с множеством похожих параметров.Вот еще одно решение:

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("..."); 
        }
    }
}

Это лучше, потому что вы не будете смешивать параметры: каждый конкретный Shape содержит свои параметры.Если вы хотите сделать его более гибким, вы можете использовать карту, чтобы переместить ответственность за переход с конкретного завода:

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;
    }
}

Я бы даже использовал 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();
    }
}

Клиент должен знать интерфейс Shape и ShapeFactory и перечисление ShapeType.«Сервер» предоставляет конкретный экземпляр ShapeFactoryImpl.

...