1. Обекти и класове

Днес ще научите малко за това How работи една типична Java програма. Ето голямата новина: всяка програма на Java се състои от класове и обекти.

Вече знаете Howво представляват класовете, но Howво представляват обектите?

Ще започна с една аналогия. Представете си, че искате да направите малък кораб. Първо трябва да създадете чертеж и след това да го дадете на фабриката, където ще бъде построен кораб според чертежа. Или може би дузина. Или колкото искате кораби. Десетки еднакви кораби се изграждат по един и същи план. Това е важното тук.

Същото е и в програмирането на Java.

Чертежи

Програмистът е като дизайнер. Дизайнер създава чертежи, а Java програмист пише класове. Частите се създават въз основа на чертежите, а обектите се създават въз основа на класове.

Първо, ние пишем класове (правим чертежи), а след това, докато програмата работи, Java машината създава обекти, базирани на тези класове. По същия начин, по който корабите се създават от чертежи.

Има само един план, но може да има много кораби. Корабите са различни - имат различни имена и превозват различни товари. Но те са много сходни: всички имат един и същ дизайн и могат да изпълняват подобни задачи.

Или ето още една аналогия...

Мравуняк

Мравуняк е добър пример за това How обектите си взаимодействат. Има три класа мравки в един обикновен мравуняк: кралицата, войниците и работниците.

Броят на мравките от всеки клас е различен. Има една кралица за целия мравуняк, но има десетки войници и стотици мравки работници. Три класа и стотици обекти. Мравките взаимодействат помежду си - с мравки от същия клас и с мравки от други класове - според строги правила.

Това е идеалният пример. Всичко е точно така в типична програма. Има първичен обект, който създава обекти от всички останали класове. Обектите започват да взаимодействат помежду си и с „външния свят“ на програмата. Поведението на обектите е вътрешно твърдо codeирано.

Тези две аналогии са двете страни на една и съща монета. Истината е по средата. Първият пример (за план и кораби) показва връзката между клас и обекти от този клас. Това е силна аналогия. Вторият пример (за мравуняк) показва връзката между написаните класове и обектите, които съществуват, докато програмата работи.

Първо трябва да напишете класове за всеки обект, който ще съществува в програмата, и след това да опишете How те взаимодействат. Да, така е, но е по-лесно, отколкото звучи.

В Java всички обекти са обекти по време на изпълнение и писането на програма е свързано с описание на различните начини, по които обектите взаимодействат. Обектите просто извикват методите на другия и им предават необходимите данни.

Документация

И откъде знаете Howви данни да предадете на методите? Хората, които са дошли преди вас, са мислor за всичко.

Всеки клас обикновено има описание, което казва за Howво е създаден. Освен това всеки публичен метод обикновено има описание, което показва Howво прави и Howви данни трябва да му бъдат предадени.

За да използвате клас, трябва да имате обща представа Howво прави. И трябва да знаете точно Howво прави всеки метод. Но изобщо не е необходимо да знаете How го прави. Това е като с магическа пръчка.

Нека да разгледаме codeа за копиране на файл:

Копиране на file c:\\data.txt във file c:\\result.txt
package com.codegym.lesson2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopy
{
   public static void main(String[] args) throws IOException
   {
      FileInputStream fileInputStream = new FileInputStream("c:\\data.txt");
      FileOutputStream fileOutputStream = new FileOutputStream("c:\\result.txt");

      while (fileInputStream.available() > 0)
      {
         int data = fileInputStream.read();
         fileOutputStream.write(data);
      }

      fileInputStream.close();
      fileOutputStream.close();
   }
}

Ако прочетете този code ред по ред, можете да познаете Howво прави в общи линии. Въпреки че това изисква опит и практика. След известно време този code ще ви се стори познат и разбираем.


2. Проектиране на програма

Проектирането на програми е цяло изкуство. Едновременно е просто и трудно. Просто, защото няма строги закони: всичко, което не е забранено, е позволено. Е, и това също го затруднява: има много начини да се направи нещо и не е лесно да се намери най-добрият.

Проектирането на програма е като писането на книга. От една страна, вие просто пишете букви, думи и изречения. От друга страна, важни са сюжетът, героите, вътрешните противоречия, конфликти, стилът на разказване, интригата и т.н.

Основното нещо е да разберете за кого пишете codeа. И пишете code за други програмисти .

Разработването на продукта неизбежно означава извършване на промени: нещо се добавя тук, нещо друго се премахва там, нещо се преработва. Ето How от малки повторения се раждат големи, огромни и гигантски проекти.

Най-важното за codeа е той да бъде разбираем за другите програмисти. Неправилен code, който е разбираем, може да бъде коригиран. Правилният, но неразбираем code не може да бъде подобрен.  Всичко, което можете да направите, е да го изхвърлите.

И така, How се пише добър, чист code?

За да направите това, са необходими три неща:

  • Писането на добър и разбираем code в методите — това е най-лесното изискване
  • Вземане на решение кои субекти да бъдат включени в програмата
  • Правилно разделяне на програмата на логически части

Какво стои зад тези концепции?

Писане на добър code вътре в методите

Ако имате дори основни познания по английски език, може би сте забелязали колко лесно понякога може да бъде четенето на code като английски изречения:

  • class Cat extends Pet— Това означава, че класът Cat разширява класа Pet
  • while(stream.ready())— стига потокът да е готов...
  • if (a<b) return a; else return b— ако ае по-малко от b, тогава връщане а, в противен случай връщане b.

Това е умишлено. Java е един от няколкото езика, които улесняват писането на самоdocumentиращ се code, т.е. code, който е разбираем без коментари. В добрия Java code много методи се четат точно като английски изречения.

Когато пишете code, вашата задача е да го направите възможно най-прост и кратък. Просто помислете дали вашият code е лесен за четене и ще започнете да се движите в правилната посока.

В Java е обичайно да се пише code, който е лесен за четене. За предпочитане е целият code за метод да се побере на един екран (т.е. 20-30 реда). Това е норма за цялата Java общност. Ако codeът може да бъде подобрен, той трябва да бъде подобрен.

Най-добрият начин да научите How да пишете добър code е чрез практика. Напишете много code, изучавайте codeа на другите и помолете по-опитни колеги да прегледат вашия code.

И помнете, че в момента, в който си кажете „оставете добре на мира“, растежът ви спира.

Вземане на решение кои субекти да бъдат включени в програмата

Трябва да напишете code, който другите програмисти могат да разберат. Ако 9 от 10 програмисти биха включor класове A, B и C в дизайна на програмата, тогава вие също трябва да направите класове A, B и C във вашата програма. Трябва да напишете code, който другите да могат да разберат.

Страхотен, работещ, бърз, но нестандартният code е лош code.

Трябва да изучавате проекти на други хора: това е най-добрият, най-бързият и най-лесният начин да попиете цялата мъдрост, натрупана в ИТ индустрията от десетилетия.

И между другото, вече имате достъп до един отличен, популярен и добре documentиран проект — Java SDK . Започнете с него.

Анализирайте класовете и How са организирани. Помислете защо някои методи са статични, а други не. Защо методите имат специфичните параметри, които имат, но не и други. Защо точно тези методи и защо класовете са именувани така, Howто са именувани, и защо се съдържат в техните специфични пакети.

След като започнете да разбирате отговорите на всички тези въпроси, ще можете да пишете code, който другите могат да разберат.

Въпреки това искам да ви предупредя да не анализирате codeа в методите на Java SDK. Много от методите са пренаписани, за да се увеличи максимално скоростта, и тяхната четимост е под въпрос.

Правилно разделяне на програмата на логически части

Почти всяка програма е разделена на части or модули. Всяка част отговаря за своя аспект на програмата.

Компютърът има дънна платка, монитор и клавиатура - всички те са отделни, слабо свързани части. Нещо повече, те си взаимодействат по стандартизирани начини: USB, HDMI и др. Ако разлеете кафе върху клавиатурата си, можете просто да я измиете в мивката, да я оставите да изсъхне и след това да продължите да я използвате.

Но лаптопът е пример за монолитна архитектура: изглежда, че можем да различим отделни логически части, но те са много по-интегрирани. На MacBookPro трябва да разглобите половината лаптоп, за да почистите клавиатурата. А разливането на кафето върху лаптопа е причина да си поръчате нов лаптоп. Не е нова чаша кафе.


3. Създаване на собствени класове

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

Разбира се, вече сте създали класове, но трябва да се научите да разбирате Howви класове трябва да бъдат включени в една програма, How трябва да бъдат наименувани и Howви методи трябва да имат. И How трябва да си взаимодействат помежду си.

Списък на субектите

Ако не знаете откъде да започнете, започнете отначало.

Когато за първи път започнете да проектирате програма, можете просто да вземете лист хартия и да напишете списък на субектите (обектите), които трябва да бъдат в програмата. И след това напишете code според принципа, че всеки обект е отделен клас.

Пример

Да приемем, че искате да напишете игра на шах. Ще ви трябват следните обекти: шахматна дъска и 6 вида шахматни фигури. Фигурите се движат по различни начини и имат различни стойности. Логично е, че те са отделни класове. Наистина, когато за първи път започнете, колкото повече класове, толкова по-добре.

Много рядко се среща начинаещ програмист, който пише десет класа instead of два. Вместо да пишат десет класа, начинаещите обичат да пишат два класа or може би само един. Така че, моля, пишете повече класове, колеги програмисти. И вашият code ще стане по-ясен за всички, освен може би за вас 😛

Шах

Да предположим, че решим да напишем класове за шах: How ще изглеждат тези класове?

Дали шахматната дъска е само масив 8 на 8? По-добре е да създадете отделен клас, който вътрешно да съхранява препратка към масив. След това можете да добавите много полезни методи към класа "шахматна дъска", например, за да проверите дали конкретна клетка е празна or заета

Като цяло, когато започнете, винаги се ръководете от този принцип: Програмата има различни обекти, а обектът има тип. Този тип е класът.


4. Статични променливи и методи

Също така не забравяйте да използвате статични променливи и методи. Ако имате една шахматна фигура, взаимодействаща с друга на шахматната дъска, вашият code се нуждае от метод, който взема препратки към първата и втората фигура, Howто и към шахматната дъска.

Статичните променливи, които могат да бъдат достъпни от всяко място в програмата, обикновено се използват, за да се избегне постоянното предаване на препратки към обекти, които "винаги съществуват".

Например така:

Код Забележка
public class ChessBoard
{
   public static ChessBoard board = new ChessBoard();
   public ChessItem[][] cells = new ChessItem[8][8];
   ...
}

public class Game
{
   public static void main(String[] args)
   {
      var board = ChessBoard.board;
      board.cells[0][3] = new King(Color.WHITE);
      board.cells[0][4] = new Queen(Color.WHITE);
      ...
   }
}


Препратка към отделен ChessBoardобект.
Двуизмерен масив 8x8, а не статична променлива.








Добавете фигурите към дъската.

Или instead of статична променлива, можете да създадете метод, който връща единичен обект. Например така:

public class ChessBoard
{
   private static ChessBoard board = new ChessBoard();
   public static ChessBoard getBoard()
   {
      return board;
   }

   public ChessItem[][] cells = new ChessItem[8][8];
   ...
}

public class Game
{
   public static void main(String[] args)
   {
      var board = ChessBoard.getBoard();
      board.cells[0][3] = new King(Color.WHITE);
      board.cells[0][4] = new Queen(Color.WHITE);
      ...
   }
}