Java - это идиома или паттерн, классы поведения без состояния - PullRequest
1 голос
/ 14 января 2011

Я пытаюсь включить более функциональные идиомы программирования в мою разработку Java. Один шаблон, который мне нравится больше всего и который избегает побочных эффектов, - это создание классов, которые имеют поведение, но не обязательно имеют какое-либо состояние. Поведение заблокировано в методах, но они действуют только на переданные параметры.

Код ниже - это код, который я пытаюсь избежать:

public class BadObject {

    private Map<String, String> data = new HashMap<String, String>();

    public BadObject() {
        data.put("data", "data");
    }

    /**
     * Act on the data class. But this is bad because we can't
     * rely on the integrity of the object's state.     
     */
    public void execute() {
        data.get("data").toString();
    }

}

Код ниже не является чем-то особенным, но я воздействую на параметры, и состояние содержится в этом классе. Мы все еще можем столкнуться с проблемами с этим классом, но это проблема с методом и состоянием данных, мы можем решать проблемы в подпрограмме, а не доверять всему объекту.

Это какая-то форма идиомы? Это похоже на любой шаблон, который вы используете?

public class SemiStatefulOOP {

    /**
     * Private class implies that I can access the members of the <code>Data</code> class
     * within the <code>SemiStatefulOOP</code> class and I can also access
     * the getData method from some other class.
     *  
     * @see Test1
     *
     */
    class Data {
        private int counter = 0;        
        public int getData() {
            return counter;
        }
        public String toString() { return Integer.toString(counter); }
    }

    /**
     * Act on the data class. 
     */
    public void execute(final Data data) {
        data.counter++;        
    }

    /**
     * Act on the data class. 
     */
    public void updateStateWithCallToService(final Data data) {
        data.counter++;       
    }

    /**
     * Similar to CLOS (Common Lisp Object System) make instance.
     */
    public Data makeInstance() {
        return new Data();
    }

} // End of Class //

Проблемы с кодом выше:

  1. Я хотел объявить класс Data закрытым, но тогда я не могу ссылаться на него вне класса:

  2. Я не могу переопределить класс SemiStateful и получить доступ к закрытым членам.

Использование:

final SemiStatefulOOP someObject = new SemiStatefulOOP();
final SemiStatefulOOP.Data data = someObject.makeInstance(); 

someObject.execute(data);
someObject.updateStateWithCallToService(data);

Edit-1: Это хороший комментарий. Мой ответ: «Как только вы сделаете класс Data доступным вне основного класса, вы раскрываете детали реализации», - комментарий.

Мой ответ: Класс Data является простым POJO и будет работать как другие pojos с сеттерами и геттерами. То, что я делал в вышеприведенном классе, пыталось манипулировать только классом Data из класса поведения SemiStatefulOOP. Я намерен иметь классы без состояния, но я хотел иметь четкое отделение от классов состояния и классов поведения.

Связанный:

Шаблон дизайна без сохранения состояния http://guides.brucejmack.biz/Pattern%20Documents/Stateless%20Design%20Pattern.htm

Ответы [ 6 ]

3 голосов
/ 14 января 2011

Существует интересный архитектурный стиль ОО, целью которого является разделение данных и поведения системы, чтобы они могли развиваться независимо: Архитектура DCI .

На практике вы создаете объекты данных для концепций вашего домена (возможно, только с простым поведением, связанным с самими данными); и объекты поведения, которые работают с объектами данных и реализуют сценарии использования системы. Эти объекты поведения рассматриваются как роли, которые могут играть доменные объекты, и материализуются с помощью концепции ОО черта (pdf) .

У Scala есть свои черты, а у Java - нет. Для этого вы можете попробовать использовать Qi4J framework в Java.

3 голосов
/ 14 января 2011

Одним из ключевых моментов ОО-программирования является то, что вы скрываете детали реализации.Похоже, ваш подход этого не делает - как только вы делаете класс Data доступным вне основного класса, вы раскрываете детали реализации и эффективно раскрываете представление данных.

Конечно, невозможно сделать всеклассы не сохраняют состояние - что-то должно содержать состояние, и мне не ясно, почему хранение его в Data предпочтительнее, чем хранение в основном классе.

Наконец, принцип ОО-программирования заключается в сохранении данных и функциональностик нему в том же месте, то есть в том же классе.Короче говоря, хотя ваше предложение интересно, я думаю, что проблемы, которые оно создает, хуже, чем проблемы, которые оно решает.

2 голосов
/ 14 января 2011

построение классов с поведением но они не обязательно имеют какие-либо состояние

См. вики

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

// The context class uses this to call the concrete strategy
interface Strategy {
    int execute(int a, int b); 
}

// Implements the algorithm using the strategy interface
class ConcreteStrategyAdd implements Strategy {

    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyAdd's execute()");
        return a + b;  // Do an addition with a and b
    }
}
1 голос
/ 14 января 2011

Я думаю, что лучшим решением для включения более функционального программирования в ваши проекты является использование функционального языка программирования, такого как Scala.Scala полностью совместима с Java и совместима с JVM.Классы Scala - это классы Java и наоборот.Почему бы не попробовать это ...:)

Java - полный ООП язык, и я считаю, что функциональные парадигмы просто не вписываются в него.

1 голос
/ 14 января 2011

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

public void execute(Map<String, String> data) {
    ...
}

или аналогичный?

В общем, когда я думаю о функциональных и / или состояниях идиомах без состоянияподавляющий шаблон кода, который возникает, состоит в том, что методы должны принимать параметры для всего, от чего они зависят (вместо того, чтобы получать их из полей или статических методов или из-за крушения поезда (getFoo().getCustomer().getAddress().getHouseName())).Это и возвращает результат, а не изменяет состояние других объектов.

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

Это не был бы один из оригинальных шаблонов GoF, но я считаю, что у Джоша Блоха есть параграф об этом в Effective Java , озаглавленный что-то вроде «Предпочитать неизменность», что достаточно броско.

0 голосов
/ 14 января 2011

Похоже, у вас есть служебные классы.

public class Data {    
    private static final Map<String, String> data = new HashMap<String, String>();
    static {
        data.put("data", "data");
    }
    private Data() { }

    /**
     * Act on the data class.     
     */
    public static void execute() {
        data.get("data").toString();
    }
}

Вам не нужно создавать объект.

Data.execute();
...