Как определить состояние объекта перед началом программирования?

#java #methodology

#java #методология

Вопрос:

У меня есть следующий код для отображения суммы двух последовательных элементов ArrayList, пока оставшийся элемент не будет равен единице.например:-
если я ввел

 1 2 3 4 5
  

вывод
3 7 5 // добавление двух последовательных последних — это как
10 5 // делать то же самое
15
код

 import java.util.*;
import java.lang.Integer;
class Substan{
     ArrayList <Integer> list = new ArrayList <Integer> ();
     ArrayList <Integer> newList = new ArrayList <Integer> ();// this will be the list containing     the next sequence.
     int index=0;
     int sum=0;
    Substan(){
        Scanner read = new Scanner(System.in);
        String choice;
        System.out.println("Enter the elements of the array");
        do{
            int element = read.nextInt();
            list.add(element);
            System.out.println("More?");
            choice = read.next();
         }while(choice.equals("y") || choice.equals("Y"));
    }
    /* precondition- we have the raw list that user has enterd.
     postcondition - we have displayed all the sublists,by adding two consecutives numbers and the last one is having one element.
     */ 
    void sublist(){         
        while(noofElementsIsNotOneInList()){
            index =0;
            while(newListIsNotComplete()){
                if(nextElementIsThere()){
                    sum = addTheConsecutive();
                }
                else{
                    sum = getLastNumber();
                }
                storeSumInNewList();    
            }
            displayTheNewList();
            System.out.println("");
            updateTheLists();
        }
       displayTheNewList(); //as we have danger of Off By One Bug (OBOB)
        System.out.println("");
    }
    private boolean noofElementsIsNotOneInList(){
        boolean isnotone = true;
        int size = list.size();
        if ( size == 1){
            isnotone = false;
        }
        return isnotone;
    }
    private boolean newListIsNotComplete(){
        boolean isNotComplete = true;
        int listSize = list.size();
        int newListSize = newList.size();
        if (listSizeIsEven()){
            if ( newListSize == listSize/2){
                isNotComplete = false;
            }
        }
        else{
            if( newListSize == (listSize/2)  1){
                isNotComplete = false;
            }
        }
        return isNotComplete;
    }
    private boolean listSizeIsEven(){
        if ( list.size()%2 == 0 ){
            return true;
        }
        else{
            return false;
        }
     }
    /*
    we are at some index.
   returns true if we have an element at (index 1) index.
    */
    private boolean nextElementIsThere(){
        if ( list.size() == index 1 ){
            return false;
        }
        else{
            return true;
        }
     }
    /* precondition-we are at index i
       postcondition - we will be at index i 2 and we return sum of elements at index i and i 1.
*/
    private int addTheConsecutive(){
        int sum = list.get(index) list.get(index 1);
        index  = 2;
        return sum;
     }
    /* we are at last element and we have to return that element.
    */
    private int getLastNumber(){
            return list.get(index);
    }
     private void storeSumInNewList(){
        newList.add(sum);
    }
     private void displayTheNewList(){
        int size = newList.size();
        for ( int i=0;i<size;i  ){
            System.out.print(newList.get(i) " ");
         }
     }
    /*precondition - we have processed all the elements in the list and added the result in newList.
      postcondition - Now my list will be the newList,as we are processing in terms of list and  newList reference will have a new object.
    */
     private void updateTheLists(){
        list = newList;
        newList = new ArrayList <Integer>();// changing the newList
     }
    public static void main(String[] args) {
        Substan s = new Substan();
        s.sublist();
    }
}     
  

Итак, я многое доработал в своем коде, но у меня возникла проблема с разделением локальных переменных с другими методами. например, я использовал index instance для хранения индекса, и изначально я думал, что я помещу это не как экземпляр, а как локальную переменную в методе sublist() , но поскольку ее нельзя просмотретьиз других методов, которые необходимо использовать index подобные addTheConsecutive() .Итак, учитывая, что я поставил index на уровне класса.Итак, это подход Райта, который помещает переменные, которые являются общими на уровне класса, вместо того, чтобы изначально смотреть только на состояние объекта перед кодированием, придерживаться этого и никогда не изменять его?

Комментарии:

1. Совместное использование индексов массивов между методами звучит немного странно, но если вам нужно это сделать, лучше сделайте это, передав индекс методу в качестве аргумента (и если он изменится — передайте его обратно как возвращаемое значение). Я не вижу никакой дополнительной ценности в объявлении его как переменной-члена класса as static .

2. @alfasin так что это не самый лучший подход для совместного использования индекса

Ответ №1:

Рассмотрим это:

Объект может взаимодействовать с другими объектами только путем совместного использования своих атрибутов. Итак, если вам нужно, чтобы объект считывал состояние другого, единственный способ сделать это — дать ему «разрешение» на чтение других атрибутов объекта.

У вас есть два способа сделать это:

  1. Объявление атрибутов объекта public или
  2. Создание getXXX() методов (имеет смысл для частных атрибутов)

Я лично предпочитаю второй вариант, потому getXXX() что метод возвращает значение («состояние») определенного атрибута без риска быть измененным. Конечно, если вам нужно изменить частный атрибут, вы также должны написать setXXX() метод.

Пример:

 public class MyClass {
    private int foo;
    private String bar;
    /*
     * Code
     */
    public int getFoo() {
        return foo;
    }
    public String getBar() {
        return bar;
    }
    public void setFoo(int foo) {
        this.foo = foo;
    }
    public void setBar(String bar) {
        this.bar = bar;
    }
    /*
     * More code
     */
} 
  

Таким образом, все атрибуты объекта инкапсулируются, и:

  1. они не могут быть прочитаны любым другим объектом, если вы специально не вызовете соответствующую getXXX() функцию, и
  2. не может быть изменен другими объектами, если вы специально не вызываете соответствующую setXXX() функцию.

Ответ №2:

Сравните его с неабстрактной версией.

         for (int index = 0; index < list.size(); index  = 2) {
            int sum = list.get(index);
            if (index   1 < list.size() {
                sum  = list.get(index   1);
            }
            newList.add(sum);
        }
  

Теперь нисходящее уточнение алгоритма с использованием имен — это надежная методология, которая помогает в дальнейшем творческом программировании.

Как видно, при повторном абстрагировании вышеизложенного:

         while (stillNumbersToProcess()) {
            int sum = sumUpto2Numbers();
            storeSumInNewList(sum);
        }
  

Можно сохранить множество переменных, например sum , в качестве локальных переменных, упрощая состояние.

Одним из видов полезной абстракции является использование условий в более непосредственной форме:

 private boolean listSizeIsEven() {
    return list.size() % 2 == 0;
}

private boolean nextElementIsThere() {
    return index   1 < list.size();
}
  

Комментарии:

1. спасибо. но единственный способ обработки индексов в этом подходе — передавать их в качестве аргументов, не так ли?

2. я новичок, так что мне придерживаться этой методологии или попробовать что-то профессиональное?

3. Да, в качестве аргумента. Существует / был академический язык программирования ELAN, который следовал вашему дизайну на курсах: index тогда он был бы в глобальной области видимости (скажем, поле java). Я думал, что ваша методология изложена в хорошем (!) курсе программирования.

4. О методологии: listSizeIsEven кажется, не требуется, когда list отображается как переменная. С другой стороны nextElementIsThere , это может помочь в объяснении алгоритма. Я часто видел код, в котором это 1 — падение с неба — требует дополнительной проверки кода. В коде также часто отсутствуют комментарии о том, что делается по какой причине.

Ответ №3:

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

Ответ №4:

Я думаю, вы задаете неправильный вопрос.

Переменные вашего класса имеют очень мало смысла, как и многие методы. Это в основном потому, что:

  1. Ваш класс делает слишком много
  2. Ваш алгоритм немного странный

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

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

Код усеян методами, в которых я не совсем вижу смысла, такими как:

 private boolean noofElementsIsNotOneInList(){
    boolean isnotone = true;
    int size = list.size();
    if ( size == 1){
        isnotone = false;
    }
    return isnotone;
}
  

Разве это не должно быть:

 private boolean noofElementsIsNotOneInList(){
    return list.size() == 1;
}
  

И для него нет смысла использовать какой-то произвольный List , передать его, чтобы вы знали, что List вы проверяете:

 private boolean noofElementsIsNotOneInList(final Collection<?> toCheck){
    return toCheck.size() == 1;
}
  

Та же логика может быть применена практически ко всем вашим методам.

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

TL; DR: использование множества коротких методов с соответствующими именами: хорошо. Наличие этих методов делает то, чего нельзя было ожидать: плохо. Наличие большого количества избыточного кода, из-за которого вещи очень трудно читать: плохо.

Фактически, просто чтобы доказать свою точку зрения, весь класс (кроме логики для чтения из stdin, которой в любом случае не должно быть) может быть преобразован в один короткий рекурсивный метод, который вообще не требует переменных экземпляра:

 public static int sumPairs(final List<Integer> list) {
    if (list.size() == 1)
        return list.get(0);
    final List<Integer> compacted = new LinkedList<>();
    final Iterator<Integer> iter = list.iterator();
    while (iter.hasNext()) {
        final int first = iter.next();
        if (iter.hasNext()) compacted.add(first   iter.next());
        else compacted.add(first);
    }
    return sumPairs(compacted);
}
  

Теперь вы могли бы разбить этот метод на несколько более коротких методов с подходящими именами, и это имело бы смысл. Иногда более полезно начинать с другого конца. Набросайте логику вашего кода и то, что он пытается сделать, затем найдите значимые фрагменты, на которые его можно разделить. Возможно, после добавления модульных тестов для проверки поведения.

Комментарии:

1. как насчет отображения каждого сжатого списка?

2. Добавьте a System.out.println(compacted) , если хотите.

3. извините! я новичок в Java и не изучал связанный список

4. Это LinkedList другая реализация List — в данном случае она ничем не отличается от an ArrayList . Доступ к нему должен осуществляться с помощью Iterator и не реализуется RandomAccess .

5. работает ли System.out.println(сжатый), если сжатый был ArrayList

Ответ №5:

как насчет выполнения рекурсии:

 public int calculateSum(List<Integer> nums) {
        displayList(nums);
        if (nums.size() == 1) {
            return nums.get(0);
        }
        List<Integer> interim = new ArrayList<Integer>();
        for (int i = 0; i < nums.size(); i = i   2) {
            if (i   1 < nums.size()) {
                interim.add(nums.get(i)   nums.get(i   1));
            } else {
                interim.add(nums.get(i));
            }
        }
        return calculateSum(interim);
    }
    public static void displayList(List<Integer> nums){
        System.out.println(nums);
    }
  

Шаги:

    Run calculate sum until list has 1 element
   if list has more than 1 element:
   iterate the list by step  2 and sum the element and put into a new List
   again call calculate sum
  

Комментарии:

1. Если вы собираетесь опубликовать ответ только для кода, который на самом деле не отвечает на вопрос, то, по крайней мере, правильно отформатируйте свой код. PS вам не нужен if...else , если у вас есть return — см. Мой ответ на (что я думаю) более элегантный подход.