Широко применяя фабричный шаблон - PullRequest
0 голосов
/ 22 ноября 2018

Я разрабатываю игру, и во многих случаях мне нужен какой-то заводской шаблон.Чтобы не создавать множество методов класса Factory, я использовал Supplier<T>.Это прекрасно работает, но не при наличии обязательных аргументов.

Это работает в этом случае: () -> new Spawn(3, 6, "example");

Но иногда мне нужно передать другие параметры на завод.Есть Consumer и BiConsumer, которые принимают два параметра.Но нет интерфейса для 3, 4, 5 ...

Я нашел смущающее решение этой проблемы, но оно иллюстрирует то, чего я пытаюсь достичь.Какие еще есть решения?

import java.util.function.Function;

public class FactoryExample {

    static class Args {
        Object[] objs;
        Args(Object ...objs) { this.objs = objs; }
        Object[] get() { return objs; }
    }

    static class Thing {
        int a; char b; boolean c;
        Thing(int a, char b, boolean c) {
            this.a = a; this.b = b; this.c = c; }
    }

    static class Number {
        int x;
        Number(int x) { this.x = x; }
    }


    public static void main(String[] args) {

        Function<Args, Number> factoryA = arg -> {
            int x = (int) arg.get()[0];
            return new Number(x);   
        };

        Function<Args, Thing> factoryB = arg -> {
            int a = (int) arg.get()[0];
            char b = (char) arg.get()[1];
            boolean c = (boolean) arg.get()[2];
            return new Thing(a, b, c);
        };

        factoryB.apply(new Args(3, 'a', true));
        factoryA.apply(new Args(3));
    }

}

Пример: как мне избежать создания этих фабрик?

public class InfectionFactory {

    private Integer damage;
    private Integer delay;
    private Integer hits;
    private Integer spikes;
    private Color color;

    public InfectionFactory setColor(Color color) {
        this.color = color;
        return this;
    }

    public InfectionFactory setSpikes(int spikes) {
        this.spikes = spikes;
        return this;
    }

    public InfectionFactory setDamage(int damage) {
        this.damage = damage;
        return this;
    }

    public InfectionFactory setDelay(int delay) {
        this.delay = delay;
        return this;
    }

    public InfectionFactory setHits(int hits) {
        this.hits = hits;
        return this;
    }

    public Infection create(Game game, Living target) {
        Infection infection = new Infection(game, target);

        if (damage  != null) infection.setDamage(damage);
        if (color   != null) infection.setColor(color);
        if (delay   != null) infection.setDelay(delay);
        if (hits    != null) infection.setHits(hits);
        if (spikes  != null) infection.setSpikes(spikes);

        return infection;
    }

}

1 Ответ

0 голосов
/ 22 ноября 2018

У вас, кажется, есть несколько требований.Прежде всего, чтобы заставить Supplier принимать все аргументы, которые вы хотите, вы можете сделать что-то вроде:

public class SpawnFactory implements Supplier<Spawn> {
  //todo: put members for all the arguments you need, make them final so that you don't miss any in the constructor

  public SpawnFactory( ... all the arguments you want ... ) {

  }

  public Spawn get() {
    return new Spawn( ... all the arguments you want ...);
  }
}

Поскольку он реализует Supplier, вы можете передать их непосредственно в экземпляр, как вам нравится.Вместо () -> new Spawn(3, 6, "example") просто сделайте new SpawnFactory(3, 6, "example");

Примером вашего InfectionFactory с другой стороны является следование шаблону построителя (вы можете переименовать его InfectionBuilder).В этом нет ничего плохого (за исключением того факта, что он кажется немного избыточным, поскольку Infection тоже использует тот же шаблон)

Возможно, вы захотите, чтобы в качестве конструктора принимались Game и Livingвместо аргументов, и тогда вашему create() не понадобятся никакие аргументы.Ваш последний шаг - создать класс implement Supplier<Infection> и добавить Infection get(), который просто вызывает create() (если вы не хотите переименовать create() в get()).

...