JavaRush /Blogue Java /Random-PT /Nível 37. Respostas às perguntas da entrevista sobre o tó...
lichMax
Nível 40
Санкт-Петербург

Nível 37. Respostas às perguntas da entrevista sobre o tópico do nível

Publicado no grupo Random-PT
Olá. Novamente, também não encontrei respostas para essas perguntas. Resolvi postar as respostas que compilei para mim. Nível 37. Respostas às perguntas da entrevista sobre o tema do nível - 1Aqui estão as perguntas reais: Perguntas para a entrevista:
  1. O que são padrões de design?
  2. Quais padrões de design você conhece?
  3. Conte-nos sobre o padrão Singleton? Como torná-lo thread-safe?
  4. Conte-nos sobre o padrão Factory?
  5. Conte-nos sobre o padrão AbstractFactory
  6. Conte-nos sobre o padrão Adaper, suas diferenças em relação ao Wrapper?
  7. Conte-nos sobre o padrão Proxy
  8. O que é um iterador? Quais interfaces relacionadas ao iterador você conhece?
  9. Por que precisamos da classe Arrays?
  10. Por que precisamos da classe Collections?
Aqui estão minhas respostas: Minhas respostas:
  1. Os padrões de projeto são soluções bem estabelecidas e bem-sucedidas para os problemas mais comuns que surgem durante o projeto e o desenvolvimento de programas ou de suas partes.

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

  3. Quando você precisa que apenas uma instância de uma classe exista em um programa, o padrão é usado Singleton. Parece assim (inicialização lenta):

    clas Singleton {
    	private Singleton instance;
    
    	private Singleton() {}
    
    	public static Singletot getInstance() {
    		if (instance == null)
    			instance = new Singleton();
    		return instance;
    	}
    }

    Para torná-lo thread-safe, você pode adicionar getInstance()um modificador ao método synchronized. Mas esta não será a melhor solução (e sim a mais simples). Uma solução muito melhor é escrever o método getInstancedesta forma (bloqueio verificado duas vezes):

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

  4. Um padrão Factoryé um padrão generativo. Permite criar objetos sob demanda (por exemplo, sob certas condições). Se parece com isso:

    class Factory{
    	public static Object1 getObject1() {
    		return new Object1();
    	}
    
    	public static Object2 getObject2() {
    		return new Object2();
    	}
    
    	public static Object3 getObject3() {
    		return new Object3();
    	}
    }

    Há também uma variação desse padrão chamada FactoryMethod. De acordo com esse padrão, diferentes objetos são criados em um método, dependendo dos dados de entrada recebidos (valores de parâmetros). Todos esses objetos devem ter um ancestral comum (ou uma interface implementável comum). Se parece com isso:

    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;
    		}
    	}
    }

    Classes Object1e herda de Object2class .Object3CommonClass

  5. Um padrão Abstract Factorytambém é um padrão de design generativo. De acordo com esse padrão, é criada uma fábrica abstrata que serve de modelo para diversas fábricas concretas. Aqui está um exemplo:

    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. Um padrão Adapteré um padrão estrutural. Sua implementação permite que um objeto de um tipo seja usado onde um objeto de outro tipo é necessário (geralmente tipos abstratos). Um exemplo de implementação deste padrão:

    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 — это структурный паттерн проектирования. Он нужен для того, чтобы контролировать доступ к Howому-то an objectу. Для этого пишется класс по типу "обёртка", то есть внутрь класса передаётся исходный an object, реализующий некий интерфейс, сам класс тоже реализует этот интерфейс, и в каждом методе этого класса вызывается похожий метод у исходного an object. Реализация того же интерфейса, что и у исходного an object, позволяет подменить исходный an object прокси-an objectом. Также это позволяет, не меняя исходного an object, "навешивать" на его методы Howую-то специальную дополнительную функциональность (например, логирование, проверка прав доступа, кэширование и т.д.). Пример:

    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. Итератор — это специальный внутренний an object коллекции, который позволяет последовательно перебирать элементы этой коллекций. Этот an object должен реализовывать интерфейс Iterator<E>, либо ListIterator<E> (для списков). Также, для того, чтобы перебирать элементы коллекции, коллекция должна поддерживать интерфейс Iterable<E>. Интерфейс Iterable<E> содержит всего один метод — iterator(), который позволяет извне получить доступ к итератору коллекции.

    Интерфейс Iterator<E> содержит следующие методы:

    • boolean hasNext() — проверяет, есть ли в коллекции ещё Howой-то элемент

    • E next() — позволяет получить очередной элемент коллекции (после получения element, внутренний курсор итератора передвигается на следующий элемент коллекции)

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

    Интерфейс же ListIterator<E> содержит такие методы:

    • boolean hasNext() — проверяет, существуют ли ещё один элемент в коллекции (следующий за текущим)

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

    • int nextIndex() — возвращает индекс следующего element

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

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

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

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

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

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

  9. A classe Arraysé uma classe utilitária projetada para uma variedade de manipulações de array. Esta classe possui métodos para transformar um array em uma lista, pesquisar em um array, copiar um array, comparar arrays, obter um hashcode de array, representar um array como uma string, etc.

  10. A classe Collectionsé uma classe utilitária para trabalhar com coleções. Esta classe possui métodos para adicionar elementos a uma coleção, preencher uma coleção com elementos, pesquisar uma coleção, copiar uma coleção, comparar uma coleção, encontrar os elementos máximos e mínimos de uma coleção, bem como métodos para obter modificações específicas de coleções de tipos conhecidos (por exemplo, você pode obter uma coleção thread-safe ou uma coleção imutável com um elemento).

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION