Skip to content

Latest commit

 

History

History
151 lines (102 loc) · 11.2 KB

README.md

File metadata and controls

151 lines (102 loc) · 11.2 KB

Среща 25 - Енумерации и конзолни цветове

💡 - Какво разгледахме днес

В днешната среща разгледахме:

  • Работа с цветове и стилове в конзолата
  • Работа с енумерации
  • Преизползване на конструктори, при наследяване
  • Оператор за множестно аргументи (...)

📚 - Ресурси и материали

🕹️ - Задачи за упражнения

Работа с цветове и стилове в конзолата

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

  • стандартни - това което пишем по принцип
  • мета символи - специални сомволни последователности, които променят резултатния текст

Мета символите са дефинирани в така наречените ANSI Escape Sequences, набор от логически символи определящи как ще изглежда стандартния текст на конзолата.

Така например ако искаме да изведем текст в червен цвят, е необходимо да добавим символа

  • \u001b[31m - за визуализация на червени букви
  • \u001b[41m - за визуализация на червен фон

на пръв поглед тези символи изглеждат странно, но те до голяма степен са намигване към миналото в което терминалните текстови интерпретатори са разполагали само и единствено с 0 и 1 ци - или иначе казано числа, за да обработват информация.

Малко по подробно можем да разбием червения цвят на следните логически единици:

  • \u001b - това е 16 - чна репрезентация на командата ESC - която казва, че следва специални мета символи, които ще променят, текста а няма да се извеждат на екрана
  • [ - това е оператор много подобен на () при методите в Java просто показва че след него следват аргументи
  • 31 - това е кода на червен цвят, който се ползва само и единствено за визуализиране на текст, респективно 41 се ползва за визуализация на фонов цвят
  • m - е оператор, който включва цветовия режим

Така например ако изпишем низа Hello World - резултата ще е червен текст.

Systme.out.print("\u001b\[31m Hello World");

Внимание - текста ще остане червен, до момента до който не сменим цвета с помоща на нова мета команда или не ползваме командата за рестартиране на цветовете \u001b[0m

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

Работа с енумерации

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

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

class Terminal {

    public static red(int styleType, String value) {

        return (styleType == 1) 
        ? "\u001b\[31m" + value
        : "\u001b\[41m" + value;
    }

}

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

class Terminal {
    public static final FOREGROUND = 1;
}

Terminal.red(Terminal.FOREGROUND, "Hello WORLD");

В контекста на сложно приложението това може да е объркващо - а ние искаме да избегнем това. За тази цел ще ползваме енумерация. Това е специална конструкция, която ни дава възможност да дефинираме специален тип с предварително дефинирани стойности, които да задължи потребителя да избере една от тях.

Декларираме енумерацията по същия начин като класа, но за разлика от него ползваме ключовата дума enum.

public enum StyleTypeEnum {

}

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

public enum StyleTypeEnum {
    FOREGROUND, BACKGROUND
}

Резултата е именувана константа, чиято стойност не е важна, но имаща задължителен характер. Понеже енумерацията е реално тип данни, можем да задължим метода да приема стойност от тип енумерация в себе си.

class Terminal {

    public static red(StyleTypeEnum styleType, String value) {

        return (styleType == StyleTypeEnum.FOREGROUND)
        ? "\u001b\[31m" + value
        : "\u001b\[41m" + value;
    }
}

// ..
Terminal.red(StyleTypeEnum.FOREGROUND, "Hello WORLD");

При този сценарии сме длъжни да ползваме константата по точно определен начин и както се казва няма мърдане както и повод за обърквация.

Преизползване на конструктори, при наследяване

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

  • данни
  • методи

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

Нека имаме проста конструкция клас GameObject който има конструктор в себе си.

class GameObject {

    protected int row;
    protected int col;

    public Parent(int row, int col) {
        this.row = row;
        this.col = col;
    }
}

За да преизползваме конструктора трябва извикаме конструктора на родителя В конструктора на наследника. Както имаме ключова дума this с която да извикаме метода от обекта, така имаме и ключова дума super с която да викнем родителското тяло.

class GamePiece {
    public GamePiece(int row, int col) {
        super(row, col)
    }
}

Примичана да трябва да наприм това е, че при създаване на обект от тип GamePiece автоматично се създава и обект от тип родителя GameObject. Ако нямаме конструктор в родителя всичко е точно, не се налага да правим никакви магии. Но в момента в който конструктора е на лице, се налага да го обслужим. Поради факта че конструктора на наследника е първото място в което започна изграждането на обекти по веригата, трябва да се знае че това е точното място в което трябва да извикаме и констурктора на нашия родител.

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