JavaRush /Blog Java /Random-PL /Poziom 37. Odpowiedzi na pytania podczas rozmowy kwalifik...
lichMax
Poziom 40
Санкт-Петербург

Poziom 37. Odpowiedzi na pytania podczas rozmowy kwalifikacyjnej na temat poziomu

Opublikowano w grupie Random-PL
Cześć. Znów również nie znalazłem odpowiedzi na te pytania. Postanowiłem opublikować odpowiedzi, które sam przygotowałem. Poziom 37. Odpowiedzi na pytania z rozmowy kwalifikacyjnej na temat poziomu - 1Oto właściwe pytania: Pytania do rozmowy kwalifikacyjnej:
  1. Czym są wzorce projektowe?
  2. Jakie znasz wzorce projektowe?
  3. Opowiedz nam o wzorcu Singletona? Jak zapewnić bezpieczeństwo wątku?
  4. Opowiedz nam o wzorze Factory?
  5. Opowiedz nam o wzorcu AbstractFactory
  6. Opowiedz nam o wzorcu Adaper i jego różnicach w stosunku do Wrappera?
  7. Opowiedz nam o wzorcu proxy
  8. Co to jest iterator? Jakie znasz interfejsy związane z iteratorem?
  9. Dlaczego potrzebujemy klasy Arrays?
  10. Dlaczego potrzebujemy klasy Kolekcje?
Oto moje odpowiedzi: Moje odpowiedzi:
  1. Wzorce projektowe to ugruntowane, skuteczne rozwiązania najczęstszych problemów pojawiających się podczas projektowania i rozwijania programów lub ich części.

  2. Singleton, Factory, Abstract Factory, Template method, Strategy, Pool, Adapter, Proxy, Bridge. MVC_

  3. 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 metody synchronized. Ale to nie będzie najlepsze rozwiązanie (ale najprostsze). Dużo lepszym rozwiązaniem jest napisanie metody getInstancew ten sposób (podwójne sprawdzenie):

    public static synchronized Singleton getInstance() {
    	if (instance == null)
    		synchronized(Singleton.class) {
    			instance = new Singleton();
    		}
    	return instance;
    }

  4. Wzorzec Factoryjest 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 Object1i Object2dziedziczą Object3z klasy CommonClass.

  5. Wzorzec Abstract Factoryjest 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();
    	}
    }

  6. Wzór Adapterjest 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 же используется два интерфейса, и класс, который оборачивает экземпяр исходного класса, реализует совсем другой инферфейс, не интерфейс исходного класса.

  7. Паттерн 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);
    	}

  8. Итератор — это специальный внутренний 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 текущего element void add(E e). Добавляет элемент в конец списка.

    • boolean hasPrevious() — проверяет, существует ли Jakой-то элемент в коллекции перед данным элементом

    • E previous() — возвращает текущий элемент коллекции и переводит курсор на предыдущий элемент коллекции

    • int previousIndex — возвращает индекс предыдущего element коллекции

    • void remove() — удаляет текущий элемент коллекции

    • void add(E e) — добавляет элемент e после текущего element коллекции

  9. Klasa Arraysjest 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.

  10. Klasa Collectionsjest 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).

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION