Циркулярная ссылка Альтернатива - PullRequest
1 голос
/ 03 октября 2019

Фон:

В настоящее время я пытаюсь создать два оператора задач. Класс SettingOperator и класс MessageOperator. Ниже я предоставил справочную информацию о том, чего я пытаюсь достичь с обоими классами.

Цель моего SettingOperator - Создает настройки проигрывателя, такие как обычное настольное приложение, и сохраняет их в файле впапка данных. Эти предпочтения могут быть обновлены с помощью команд проигрывателя, файлов конфигурации и т. Д.

Назначение моего MessageOperator - Обрабатывает протоколирование локализованных сообщений и настраивает текущий языковой стандарт плагинов (если он в настоящее время поддерживаетсяв противном случае плагин по умолчанию используется английский).

Проблема:

В настоящее время я инициализирую оба оператора как таковые в методе onEnable ()

private static PluginName instance;
private SettingOperator setting;
private MessageOperator message;

@Override
public void onEnable() {
    instance = this;

    // TASK OPERATORS
    setting = new SettingOperator(this);
    message = new MessageOperator(this);
}

/* CLASS INSTANCES */

@Contract (pure = true)
public static AdminConsole getInstance() {
    return instance;
}

public static SettingOperator getSettingOP() {
    return setting;
}

public static MessageOperator getMessageOP() {
    return message;
}

Затем я пытаюсь назвать ссылки на оба класса, потому что оба используют друг друга взаимозаменяемо.

*** These Classes Are Into Separate Files, but for the sake of easy readability, I put them in one code block ***

public class SettingOperator {
    private final MessageOperator message = PluginName.getMessageOP();
}

public class MessageOperator {
    private final SettingOperator message = PluginName.getSettingOP();
}

Вопрос:

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

Ответы [ 2 ]

0 голосов
/ 04 октября 2019

Проблема с вашим примером кода состоит в том, что при создании экземпляра SettingOperator он вызывает PluginName.getMessageOP() до того, как будет создан экземпляр MessageOperator, поэтому вызов возвращает null, и SettingOperator никогда не получает ссылку на MessageOperator.

Вместо созданияэто так, что SettingOperator и MessageOperator пытаются сразу получить ссылку друг на друга, что невозможно, вы можете сделать это так, чтобы каждому из них для начала нужна была только ссылка на основной класс плагина, и они извлекали ссылку на другого оператораиз основного экземпляра плагина только при необходимости.

Вот пример с исправленной проблемой. В этом примере вы видите, что SettingOperator использует метод MessageOperator. (MessageOperator также может использовать SettingOperator таким же образом.)

public class PluginFoo extends JavaPlugin {
    private SettingOperator setting;
    private MessageOperator message;

    @Override
    public void onEnable() {
        setting = new SettingOperator(this);
        message = new MessageOperator(this);
    }

    public SettingOperator getSettingOP() {
        return setting;
    }

    public MessageOperator getMessageOP() {
        return message;
    }
}

public class SettingOperator {
    private final PluginFoo plugin;
    public SettingOperator(PluginFoo plugin) {
        this.plugin = plugin
    }
    public featureA() {
        System.out.println("SettingOperator featureA");
        plugin.getMessageOP().helperForFeatureA();
    }
}

public class MessageOperator {
    private final PluginFoo plugin;
    public MessageOperator(PluginFoo plugin) {
        this.plugin = plugin;
    }
    public helperForFeatureA() {
        System.out.println("MessageOperator helperForFeatureA");
    }
}
0 голосов
/ 03 октября 2019

Использовать прослушиватель событий.

Вот идея.

public interface PropertyChangeListener {
    void onPropertyChanged(Object source, String propertyName, String propertyValue);
}

public class SettingOperator implements PropertyChangeListener {

    private PropertyChangeListener listener;

    public void setPropertyChangeListener(PropertyChangeListener listener){
        this.listener = listener;
    }

    public void onPropertyChanged(Object source, String propertyName, String propertyValue) {
        if(!Objects.equal(getProperty(key), value)) {
            setProperty(key, value);
        }
    }

    public void setSetting(String key, String value){
        properties.setProperty(key, value);
        listener.onPropertyChanged(this, key, value);
    }
}

public class MessageOperator implements PropertyChangeListener {

    private PropertyChangeListener listener;

    public void setPropertyChangeListener(PropertyChangeListener listener){
        this.listener = listener;
    }

    public void onPropertyChanged(Object source, String propertyName, String propertyValue) {
        consoleLog("Property Set)";
    }

    public void setLocale(String key, String value){
        listener.onPropertyChanged(this, key, value);
    }
}


public void onEnable() {
    instance = this;
    // TASK OPERATORS
    setting = new SettingOperator(this);
    message = new MessageOperator(this);
    setting.setPropertyChangeListener(message);
    message.setPropertyChangeListener(setting);
}

Вы можете расширить метод onPropertyChanged и использовать некоторый компонент в качестве события вместо String. Также вы можете расширить его и добавить в класс не одного слушателя, а множественного. Но идея та же.

...