JavaRush /جاوا بلاگ /Random-SD /NULL خراب ڇو آهي؟
Helga
سطح

NULL خراب ڇو آهي؟

گروپ ۾ شايع ٿيل

NULL خراب ڇو آهي؟

هتي جاوا ۾ NULL استعمال ڪرڻ جو هڪ سادي مثال آهي: public Employee getByName(String name) { int id = database.find(name); if (id == 0) { return null; } return new Employee(id); } هن طريقي سان ڇا غلط آهي؟ اھو واپس ڪري سگھي ٿو NULL ھڪڙي اعتراض جي بدران - اھو اھو آھي جيڪو غلط آھي. NULL استعمال ڪرڻ OOP ۾ هڪ خوفناڪ عمل آهي ۽ هر قيمت کان بچڻ گهرجي. هن مسئلي تي ڪافي مختلف رايا اڳ ۾ ئي شايع ٿي چڪا آهن، جن ۾ ٽوني هوئر جي پيشڪش ”زيرو لنڪس: هڪ بلين ڊالر جي غلطي“ ۽ ڊيوڊ ويسٽ جو سڄو ڪتاب ”آبجڪٽ-اورينٽيڊ ٿنڪنگ“ شامل آهن. هتي مان ڪوشش ڪندس ته سڀني دليلن کي اختصار ڪري ۽ مثال ڏيکاريان ته ڪيئن توهان NULL استعمال ڪرڻ کان پاسو ڪري سگهو ٿا ان کي مناسب اعتراض تي مبني تعميرات سان تبديل ڪندي. پهرين، اچو ته ڏسو NULL جا ٻه ممڪن متبادل. پهريون آهي Null Object ڊيزائن جو نمونو (بهترين طريقي سان لاڳو ڪيو ويو آهي): public Employee getByName(String name) { int id = database.find(name); if (id == 0) { return Employee.NOBODY; } return Employee(id); } ٻيو ممڪن متبادل اهو آهي ته "تيزي سان ناڪام" ڪيو وڃي هڪ استثنا اڇلائي جيڪڏهن اعتراض واپس نه ٿو ڪري سگهجي: public Employee getByName(String name) { int id = database.find(name); if (id == 0) { throw new EmployeeNotFoundException(name); } return Employee(id); } هاڻي اچو ته NULL استعمال ڪرڻ جي خلاف دليلن تي نظر وجهون هن لکڻ کان اڳ. پوسٽ، مون کي واقف ٿي ويو، ٽوني هوئر جي مٿي بيان ڪيل پيشڪشن کان علاوه ۽ ڊيوڊ ويسٽ جي ڪتاب، ڪيترن ئي اشاعتن سان. اهي آهن ”ڪلين ڪوڊ“ رابرٽ مارٽن جو، اسٽيو ميڪنيل جو ”ڪلين ڪوڊ“ ، جان سونميز جو ”سائي ڪو نه ته NULL“ ، ۽ اسٽيڪ اوور فلو تي بحث جنهن کي ”ڇا ريٽرننگ NULL هڪ خراب مشق آهي؟
دستي طور تي غلطيون سنڀالڻ
هر دفعي توهان هڪ اعتراض ان پٽ جي طور تي وصول ڪندا آهيو، توهان کي چيڪ ڪرڻ گهرجي ته ڇا اهو هڪ حقيقي اعتراض يا NULL جو حوالو آهي. جيڪڏهن توهان چيڪ ڪرڻ وساريو ٿا، توهان جو پروگرام وچ ۾ عمل ۾ مداخلت ڪري سگهي ٿو اڇلائي NullPointerExeption (NPE). انهي جي ڪري، توهان جو ڪوڊ ڪيترن ئي چيڪن سان ڀرڻ شروع ٿئي ٿو ۽ جيڪڏهن / پوء / ٻي شاخون. // this is a terrible design, don't reuse Employee employee = dept.getByName("Jeffrey"); if (employee == null) { System.out.println("can't find an employee"); System.exit(-1); } else { employee.transferTo(dept2); } اهڙيءَ طرح استثناءَ کي C ۽ ٻين سخت طريقي سان پروگرامنگ ٻولين ۾ سنڀاليو وڃي. او او پي ۾، استثناء جي سنڀال متعارف ڪرايو ويو خاص طور تي دستي طور تي لکيل پروسيسنگ بلاڪ کان نجات حاصل ڪرڻ لاء. او او پي ۾، اسان استثنا کي بلبل ڪرڻ جي اجازت ڏيندا آهيون جيستائين اهي ايپليڪيشن-وائڊ ايرر هينڊلر تائين پهچي وڃن، ۽ اهو اسان جو ڪوڊ تمام صاف ۽ ننڍو بڻائي ٿو: dept.getByName("Jeffrey").transferTo(dept2); NULL حوالن تي غور ڪريو پروسيسنگ پروگرامنگ انداز جي هڪ رزمي ۽ استعمال ڪريو 1) Null Objects يا 2) استثنا بدران. .
مبهم سمجھ
Whatбы точно передать в названии смысл происходящего, метод getByName() должен быть переименован в getByNameOrNullIfNotFound(). То же самое нужно сделать для каждого метода, который возвращает an object or NULL, иначе при чтении codeа не избежать неоднозначности. Таким образом, для того, чтобы названия методов были точны, вы должны давать методам более длинные имена. Whatбы избежать неоднозначности всегда возвращайте реальный an object, нулевой an object or выбрасывайте исключение. Кто-то может возразить, что иногда нам просто необходимо возвратить NULL чтобы добиться нужного результата. Например, метод get() интерфейса Map в Java возвращает NULL, когда в Map нет больше an objectов. Employee employee = employees.get("Jeffrey"); if (employee == null) { throw new EmployeeNotFoundException(); } return employee; Благодаря использованию NULL в Map этому codeу хватает всего одного цикла поиска для получения результата. Если мы перепишем Map таким образом, чтобы метод get() выбрасывал исключение в случае, если ничего не найдено, наш code будет выглядеть так: if (!employees.containsKey("Jeffrey")) { // first search throw new EmployeeNotFoundException(); } return employees.get("Jeffrey"); // second search Очевидно, что этот метод в два раза медленнее, чем исходный. What же делать? В интерфейсе Map (без намерения обидеть разработчиков) есть недостаток проектирования. Его метод get() должен был бы возвращать Iterator, и тогда наш code выглядел бы так: Iterator found = Map.search("Jeffrey"); if (!found.hasNext()) { throw new EmployeeNotFoundException(); } return found.next(); Кстати, именно так спроектирован метод STL map::find() в С++.
Компьютерное мышление против an objectно-ориентированного
Строка codeа if (employee == null) вполне понятна тому, кто знает, что an object в Java – это указатель на структуру данных, а NULL – это указатель на ничто (в процессорах Intel x86 – 0x00000000). Однако если вы начнете мыслить в an objectном стиле, эта строка становится намного менее осмысленной. Вот How наш code выглядит с an objectной точки зрения:
- Здравствуйте, это отдел разработки ПО? - Да. - Будьте добры, пригласите к телефону вашего сотрудника Джефри. - Подождите minutesку... - Здравствуйте. - Вы NULL?
Последний вопрос звучит немного странно, не так ли? Если instead of этого после вашей просьбы пригласить к телефону Джефри на том конце просто повесят трубку, это вызовет для нас определенные сложности (Исключение). В этом случае мы можем попробовать перезвонить or же доложим нашему начальнику о том, что мы не смогли поговорить с Джефри, и завершим свою основную задачу. Кроме этого, на той стороне вам могут предложить поговорить с другим человеком, который, хоть и не является Джефри, может либо помочь вам с большинством ваших вопросов, либо отказаться помогать, если нам нужно узнать что-то, что знает только Джефри (Нулевой Объект).
Медленный провал
Вместо быстрого завершения работы, code выше пытается умереть медленно, убивая других на своем пути. Вместо того, чтобы дать всем понять, что что-то пошло не так и нужно немедленно начинать обработку исключительного события, он пытается скрыть свой провал от клиента. Это очень похоже на ручную обработку исключений, о которой мы говорor выше. Делать свой code How можно более хрупким и позволять ему прерываться, если это нужно – хорошая практика. Делайте свои методы предельно требовательными к данным, с которыми они работают. Позволяйте им жаловаться, выкидывая исключения, если данных, которые им предоставor, недостаточно, or же данные просто не подходят для использования в этом методе по задуманному сценарию. В противном случае возвращайте Нулевой Объект, который ведет себя Howим-то общепринятым способоы и выбрасывает исключения во всех других случаях. public Employee getByName(String name) { int id = database.find(name); Employee employee; if (id == 0) { employee = new Employee() { @Override public String name() { return "anonymous"; } @Override public void transferTo(Department dept) { throw new AnonymousEmployeeException( "I can't be transferred, I'm anonymous" ); } }; } else { employee = Employee(id); } return employee; }
Изменяемые и незавершенные an objectы
Вообще, строго рекомендуется проектировать an objectы так, чтобы они были неизменяемыми. Это значит, an object должен получить все необходимые данные при его создании и никогда не менять своего состояния в течение всего жизненного цикла. Значения NULL очень часто используются в паттерне проектирования «Ленивая загрузка» для того, чтобы сделать an objectы незавершенными и изменяемыми. Пример: public class Department { private Employee found = null; public synchronized Employee manager() { if (this.found == null) { this.found = new Employee("Jeffrey"); } return this.found; } } Несмотря на то, что эта технология широко распространена, для ООП она является антипаттерном. И главным образом потому, что заставляет an object нести ответственность за проблемы с производительностью у вычислительной платформы, а это How раз то, о чем an object Employee не может быть осведомлен. Вместо того, чтобы управлять своим состоянием и вести себя соответствующим своему предназначению образом, an object вынужден заботиться о кэшировании своих собственных результатов – вот к чему приводит «ленивая загрузка». А ведь кэширование – это вовсе не то, чем занимается сотрудник в офисе, не так ли? Выход? Не используйте «ленивую загрузку» таким примитивным способом, How в вышеприведенном примере. Вместо этого переместите кэширование проблем на другой уровень своего applications. Например, в Java вы можете использовать возможности аспектно-ориентированного программирования. Например, в jcabi-aspects есть annotation @Cacheable, которая кэширует meaning, возвращаемое методом. import com.jcabi.aspects.Cacheable; public class Department { @Cacheable(forever = true) public Employee manager() { return new Employee("Jacky Brown"); } } Надеюсь, этот анализ был достаточно убедителен, чтобы вы прекратor обNULLять свой code :) Оригинал статьи здесь. Вам также могут быть интересны такие темы How: • DI Containers are Code PollutersGetters/Setters. Evil. Period.Anti-Patterns in OOPAvoid String ConcatenationObjects Should Be Immutable
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION