Оба эти класса поддерживают инкапсуляцию и ...? - PullRequest
2 голосов
/ 03 июля 2011
public class Normal {
   public string name;     // name is public

   public String getName() {
        return name ;
   }

   public  String setName(String newName) {
         name = newName ;
         return name ;
   }

   public static void main(String args[]) {
      Normal normal = new Normal();
      normal.setName("suhail gupta");
      System.out.println( "My name is : " + normal.getName() );    
  }
 } 

Отсюда начинается новый класс

public class Different {
   private string name;         // name is private

   public String getName() {
        return name ;
   }

   public  String setName(String newName) {
         name = newName ;
         return name ; 
   }

   public static void main(String args[]) {
      Different different = new Different();
      different.setName("suhail gupta");
      System.out.println( "My name is : " + different.getName() );    
  }
 } 

Первый класс имеет имя , объявленное public, а другой класс имеет имя, объявленное private . Оба класса выполняют одну и ту же работу, но имеют только спецификаторы доступа для разных имен. Теперь,

Мои вопросы?

  • Оба класса поддерживают инкапсуляцию? Если они это делают, почему private предпочтительнее, чем public? (я проделал ту же работу, объявив имя публично, как я объявил private)
  • Какой класс легче поддерживать?
  • С какими классными программистами будет легко во время refactoring?
  • Чем normal класс отличается от different класс?
  • Когда они говорят, что Unencapsulated означает неизменяемый , как он неизменен здесь?

Ответы [ 3 ]

5 голосов
/ 03 июля 2011

В "Normal" (в этом нет ничего "нормального"), это совершенно правильный код:

public static void main(String args[]) {
   Normal normal = new Normal();
   normal.name = "suhail gupta";
   System.out.println( "My name is : " + normal.name );    
}

Ваш интерфейс теперь включает в себя значение String, называемоеname.Пользователи ожидают, что смогут установить его, используя синтаксис VarName.name или VarName.setName.Пользователи ожидают, что смогут получить его либо с помощью VarName.name или VarName.getName;

Например, это допустимо в "Normal":

public static void main(String args[]) {
   Normal normal = new Normal();
   normal.name = null;
   String name = normal.name;
   System.out.println( "My name is : " + name );
}

Теперь, возможно,ты подумаешь "ну и что?"Представьте, что значение переменной, равное null, отделено от фактической печати (где происходит ошибка) 30 файлами.Будет очень трудно узнать, кто облажался со значением этой переменной.И ничего вы не можете сделать, чтобы пользователь не испортил его.

Теперь, если вы реализовали setName следующим образом:

public String setName(String newName) {
   assert newName;
   name = newName ;
   return name ;
}

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

Конечно, это не помогает, потому что пользователь "Normal" не должен используйте setName.Они могут свободно тыкать в name напрямую.

Хотя это технически может быть инкапсуляция, насколько я понимаю, если пользователь может легко и тривиально разрушить ее, это не инкапсуляция.Если нет защиты, нет инкапсуляции.


Когда они говорят, что Unencapsulated означает «неизменяемый», как он неизменен здесь?

Хорошо, допустим, вы даете мнебиблиотека, содержащая Normal.Я буду использовать это каким-то образом.Возможно, у меня есть Normal экземпляра, разбросанных по 50 файлам.Они все устанавливаются напрямую и получают имя по name, а не по методам доступа.Это совершенно законно, потому что вы сделали это public.

Теперь, по любой причине, вы решаете, что не хотите хранить имя в строке.Может быть, вам нужно иметь имя и фамилию.Итак, допустим, что следующая версия вашей библиотеки имеет следующее определение:

public class Normal
{
    public string firstName;
    public string lastName;

    public String getName()
    {
        return firstName + " " + lastName;
    }

    public  String setName(String newName)
    {
        //parse newName into a first and last name.
        ...
        firstName = newFirstName;
        lastName = newLastName;
        return getName();
    }
}

Чего не хватает?public String name; Это больше не доступно, потому что теперь у вас есть имя и фамилия.Обратите внимание, что два метода доступа вообще не изменились .

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

И если бы вы только что сделали все правильно, ничего бы не случилось.

3 голосов
/ 03 июля 2011
  • Идея методов получения и установки заключается в том, чтобы позволить разработчикам выполнять другую необходимую логику для получения значения для поля класса.Поэтому оставление полей класса как открытых позволяет пропустить выполнение логики перед присвоением значения этому полю.

  • Второй класс легче поддерживать, так как можно быть уверенным, что значениеПеременная name всегда задается через установщик.

  • Опять второй класс лучше для перефакторинга, так как он предоставляет меньше членов.

  • ЕслиВы представляете, что какой-то другой разработчик использует «обычный» класс, он может установить значение name напрямую, а не использовать setter.Поэтому, если в будущем вы решите изменить видимость переменной name, вы нарушите код других лиц.В таком простом примере это не важно, но при написании важного кода это становится проблематичным, поскольку вы не хотите нарушать код других разработчиков, изменяя видимость переменной.Следовательно, не инкапсулированный код является неизменяемым.

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

0 голосов
/ 03 июля 2011
  1. Different - лучший пример инкапсуляции, чем Normal, хотя с чем-то таким простым преимущества не особо заметны.

  2. Different теоретически проще поддерживать, потому что если вы хотите изменить внутреннее представление name, вы можете без изменения общедоступного API.

  3. То же, что и № 2, по тем же причинам.

  4. В то время как первый класс позволяет пользователям напрямую изменять name, второй заставляет их проходить через getName() и setName().

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

...