- Czym są wzorce projektowe?
- Jakie znasz wzorce projektowe?
- Opowiedz nam o wzorcu Singletona? Jak zapewnić bezpieczeństwo wątku?
- Opowiedz nam o wzorze Factory?
- Opowiedz nam o wzorcu AbstractFactory
- Opowiedz nam o wzorcu Adaper i jego różnicach w stosunku do Wrappera?
- Opowiedz nam o wzorcu proxy
- Co to jest iterator? Jakie znasz interfejsy związane z iteratorem?
- Dlaczego potrzebujemy klasy Arrays?
- Dlaczego potrzebujemy klasy Kolekcje?
-
Wzorce projektowe to ugruntowane, skuteczne rozwiązania najczęstszych problemów pojawiających się podczas projektowania i rozwijania programów lub ich części.
-
Singleton
,Factory
,Abstract Factory
,Template method
,Strategy
,Pool
,Adapter
,Proxy
,Bridge
.MVC
_ -
Jeśli potrzebujesz, aby w programie istniała tylko jedna instancja klasy, używany jest wzorzec
Singleton
. Wygląda to tak (leniwa inicjalizacja):clas Singleton { private Singleton instance; private Singleton() {} public static Singletot getInstance() { if (instance == null) instance = new Singleton(); return instance; } }
Aby zapewnić bezpieczeństwo wątków, możesz dodać
getInstance()
modyfikator do metodysynchronized
. Ale to nie będzie najlepsze rozwiązanie (ale najprostsze). Dużo lepszym rozwiązaniem jest napisanie metodygetInstance
w ten sposób (podwójne sprawdzenie):public static synchronized Singleton getInstance() { if (instance == null) synchronized(Singleton.class) { instance = new Singleton(); } return instance; }
-
Wzorzec
Factory
jest wzorcem generatywnym. Umożliwia tworzenie obiektów na żądanie (na przykład pod pewnymi warunkami). To wygląda tak:class Factory{ public static Object1 getObject1() { return new Object1(); } public static Object2 getObject2() { return new Object2(); } public static Object3 getObject3() { return new Object3(); } }
Istnieje również odmiana tego wzoru zwana
FactoryMethod
. Według tego wzorca w jednej metodzie tworzone są różne obiekty, w zależności od wpływających danych wejściowych (wartości parametrów). Wszystkie te obiekty muszą mieć wspólnego przodka (lub wspólny implementowalny interfejs). To wygląda tak:class FactoryMethod { public enum TypeObject { TYPE1, TYPE2, TYPE3 } public static CommonClass getObject(TypeObject type) { switch(type) { case TYPE1: return new Object1(); case TYPE2: return new Object2(); case TYPE3: return new Object3(); default: return null; } } }
Klasy
Object1
iObject2
dziedzicząObject3
z klasyCommonClass
. -
Wzorzec
Abstract Factory
jest także generatywnym wzorcem projektowym. Według tego schematu powstaje abstrakcyjna fabryka, która służy jako szablon dla kilku betonowych fabryk. Oto przykład:class Human {} class Boy extends Human {} class TeenBoy extends Human {} class Man extends Human {} class OldMan extends Human {} class Girl extends Human {} class TeenGirl extends Human {} class Woman extends Human {} class OldWoman extends Human {} interface AbstractFactory { Human getPerson(int age); } class FactoryMale implements AbstractFactory { public Human getPerson(int age) { if (age < 12) return new Boy(); if (age >= 12 && age <= 20) return new TeenBoy(); if (age > 20 && age < 60) return new Man(); return new OldMan(); } } сlass FactoryFemale implements AbstractFactory { public Human getPerson(int age) { if (age < 12) return new Girl(); if (age >= 12 && age <= 20) return new TeenGirl(); if (age > 20 && age < 60) return new Woman(); return new OldWoman(); } }
-
Wzór
Adapter
jest wzorem strukturalnym. Jego implementacja pozwala na użycie obiektu jednego typu, gdy wymagany jest obiekt innego typu (zwykle typy abstrakcyjne). Przykładowa implementacja tego wzorca:interface TotalTime { int getTotalSeconds(); } interface Time { int getHours(); int getMinutes(); int getSeconds(); } class TimeAdapter extends TotalTime { private Time time; public TimeAdapter(Time time) { this.time = time; } public int getTotalTime() { return time.getSeconds + time.getMinutes * 60 + time.getHours * 60 * 60; } } class TotalTimeAdapter extends Time { private TotalTime totalTime; public TotalTimeAdapter(TotalTime totalTime) { this.totalTime = totalTime; } public int getSeconds() { return totalTime % 60; } public int getMinutes() { return (totalTime / 60) % 60; } public int getHours() { return totaltime/ (60 * 60) ; } } class Main { public static void main(String[] args) { Time time = new Time() { public int getSeconds() { return LocalTime.now().getSecond(); } public int getMinutes() { return LocalTime.now().getMinute(); } public int getHours() { return LocalTime.now().getHour() ; } }; TotalTime totalTime = new TimeAdapter(time); System.out.println(totalTime.getTotalSeconds()); TotalTime totalTime2 = new TotalTime() { public int getTotalSeconds() { LocalTime currTime = LocalTime.now(); return currTime.getSecond() + currTime.getMinute * 60 + currTime.getHour * 60 * 60; } }; Time time2 = new TotalTimeAdapter(totalTime2); System.out.println(time2.getHours + ":" + time2.getMinutes() + ":" + time2.getSeconds()); } }
При реализации паттерна
Wrapper
создаётся класс, который оборачивает исходный класс и реализует тот же интерфейс, который реализует исходный класс. Таким образом, это позволяет расширить функциональность исходного класса и использовать новый класс там, где ожидается использование исходного класса. Это отличается от реализации паттернаAdapter
тем, что в данном случае используется один интерфейс (тот же, что есть у исходного класса). В паттернеAdapter
же используется два интерфейса, и класс, который оборачивает экземпяр исходного класса, реализует совсем другой инферфейс, не интерфейс исходного класса. -
Паттерн
Proxy
— это структурный паттерн проектирования. Он нужен для того, чтобы контролировать доступ к Jakому-то obiektу. Для этого пишется класс по типу "обёртка", то есть внутрь класса передаётся исходный obiekt, реализующий некий интерфейс, сам класс тоже реализует этот интерфейс, и в каждом методе этого класса вызывается похожий метод у исходного obiektа. Реализация того же интерфейса, что и у исходного obiektа, позволяет подменить исходный obiekt прокси-obiektом. Также это позволяет, не меняя исходного obiektа, "навешивать" на его методы Jakую-то специальную дополнительную функциональность (например, логирование, проверка прав доступа, кэширование и т.д.). Пример:interface Bank { void setUserMoney(User user, double money); double getUserMoney(User user); } class CitiBank implements Bank { //оригинальный класс public void setUserMoney(User user, double money) { UserDAO.update(user,money); } public double getUserMoney(User user) { UserDAO.getUserMoney(user); } } class SecurityProxyBank implements Bank { private Bank bank; public SecurityProxyBank(Bank bank) { this.bank = bank; } public void setUserMoney(User user, double money) { if (!SecurityManager.authorize(user,BankAccounts.Manager) throw new SecurityException("User can't change money value"); UserDAO.update(user,money); } public double getUserMoney(User user) { if (!SecurityManager.authorize(user,BankAccounts.Manager) throw new SecurityException("User can't get money value"); UserDAO.getUserMoney(user); }
-
Итератор — это специальный внутренний obiekt коллекции, который позволяет последовательно перебирать элементы этой коллекций. Этот obiekt должен реализовывать интерфейс
Iterator<E>
, либоListIterator<E>
(для списков). Также, для того, чтобы перебирать элементы коллекции, коллекция должна поддерживать интерфейсIterable<E>
. ИнтерфейсIterable<E>
содержит всего один метод —iterator()
, который позволяет извне получить доступ к итератору коллекции.Интерфейс
Iterator<E>
содержит следующие методы:-
boolean hasNext()
— проверяет, есть ли в коллекции ещё Jakой-то элемент -
E next()
— позволяет получить очередной элемент коллекции (после получения element, внутренний курсор итератора передвигается на следующий элемент коллекции) -
void remove()
— удаляет текущий элемент из коллекции
Интерфейс же
ListIterator<E>
содержит такие методы:-
boolean hasNext()
— проверяет, существуют ли ещё один элемент в коллекции (следующий за текущим) -
E next()
— возвращает очередной элемент коллекции (и передвигает внутренний курсок итератора на следующий элемент) -
int nextIndex()
— возвращает индекс следующего element -
void set(E e)
— устанавливает oznaczający текущего elementvoid add(E e)
. Добавляет элемент в конец списка. -
boolean hasPrevious()
— проверяет, существует ли Jakой-то элемент в коллекции перед данным элементом -
E previous()
— возвращает текущий элемент коллекции и переводит курсор на предыдущий элемент коллекции -
int previousIndex
— возвращает индекс предыдущего element коллекции -
void remove()
— удаляет текущий элемент коллекции -
void add(E e)
— добавляет элемент e после текущего element коллекции
-
-
Klasa
Arrays
jest klasą narzędziową przeznaczoną do różnorodnych manipulacji tablicami. Ta klasa zawiera metody przekształcania tablicy w listę, przeszukiwania tablicy, kopiowania tablicy, porównywania tablic, uzyskiwania kodu skrótu tablicy, reprezentowania tablicy jako ciągu znaków itp. -
Klasa
Collections
jest klasą narzędziową do pracy z kolekcjami. Klasa ta posiada metody umożliwiające dodawanie elementów do kolekcji, wypełnianie kolekcji elementami, przeszukiwanie kolekcji, kopiowanie kolekcji, porównywanie kolekcji, znajdowanie maksymalnych i minimalnych elementów kolekcji, a także metody uzyskiwania określonych modyfikacji kolekcji znane typy (na przykład możesz uzyskać kolekcję bezpieczną dla wątków lub kolekcję niezmienną z jednym elementem).
GO TO FULL VERSION