JavaRush /Java Blog /Random EN /Level 37. Answers to interview questions on the level top...
lichMax
Level 40
Санкт-Петербург

Level 37. Answers to interview questions on the level topic

Published in the Random EN group
Hello. Again, I did not find answers to these questions either. I decided to post the answers that I compiled for myself. Level 37. Answers to interview questions on the topic of level - 1Here are the actual questions: Questions for the interview:
  1. What are design patterns?
  2. What design patterns do you know?
  3. Tell us about the Singleton pattern? How to make it thread safe?
  4. Tell us about the Factory pattern?
  5. Tell us about the AbstractFactory pattern
  6. Tell us about the Adaper pattern, its differences from Wrapper?
  7. Tell us about the Proxy pattern
  8. What is an iterator? What interfaces related to iterator do you know?
  9. Why do we need the Arrays class?
  10. Why do we need the Collections class?
Here are my answers: My answers:
  1. Design patterns are well-established, successful solutions to the most common problems that arise during the design and development of programs or their parts.

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

  3. When you need only one instance of a class to exist in a program, the pattern is used Singleton. It looks like this (lazy initialization):

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

    To make it thread safe, you can add getInstance()a modifier to the method synchronized. But this will not be the best solution (but the simplest). A much better solution is to write the method getInstancethis way (double-checked locking):

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

  4. A pattern Factoryis a generative pattern. It allows you to create objects on demand (for example, under certain conditions). It looks like this:

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

    There is also a variation of this pattern called FactoryMethod. According to this pattern, different objects are created in one method, depending on the incoming input data (parameter values). All these objects must have a common ancestor (or a common implementable interface). It looks like this:

    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 Object1, Object2and Object3inherit from class CommonClass.

  5. A pattern Abstract Factoryis also a generative design pattern. According to this pattern, an abstract factory is created that serves as a template for several concrete factories. Here's an example:

    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. A pattern Adapteris a structural pattern. Its implementation allows an object of one type to be used where an object of another type is required (usually abstract types). An example implementation of this pattern:

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

    When implementing a pattern Wrapper, a class is created that wraps the original class and implements the same interface that the original class implements. Thus, it allows you to extend the functionality of the original class and use the new class where the original class is expected to be used. This differs from implementing a pattern Adapterin that in this case a single interface is used (the same as the original class). The pattern Adapteruses two interfaces, and the class that wraps an instance of the original class implements a completely different interface, not the interface of the original class.

  7. A pattern Proxyis a structural design pattern. It is needed to control access to some object. To do this, a class is written as a “wrapper”, that is, an original object that implements a certain interface is passed inside the class, the class itself also implements this interface, and in each method of this class a similar method is called on the original object. Implementing the same interface as the original object allows you to replace the original object with a proxy object. This also allows, without changing the original object, to “attach” some special additional functionality to its methods (for example, logging, checking access rights, caching, etc.). Example:

    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 iterator is a special internal object of a collection that allows you to sequentially iterate through the elements of this collection. This object must implement the interface Iterator<E>, or ListIterator<E>(for lists). Also, in order to iterate over the elements of a collection, the collection must support the Iterable<E>. The interface Iterable<E>contains only one method iterator(), which allows you to access the collection iterator from the outside.

    The interface Iterator<E>contains the following methods:

    • boolean hasNext()— checks whether there is another element in the collection

    • E next()— allows you to get the next element of the collection (after receiving the element, the internal iterator cursor moves to the next element of the collection)

    • void remove()- removes the current element from the collection

    Интерфейс же 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. Класс Arrays — это утorтарный класс, предназначенный для разнообразных манипуляций с массивами. В этом классе есть методы превращения массива в список, поиска по массиву, копирования массива, сравнения массивов, получения хешcodeа массива, представление массива в виде строки и др.

  10. Класс Collections — это утorтарный класс для работы с коллекциями. В этом классе есть методы добавления элементов в коллекцию, наполнения коллекции elementми, поиска по коллекции, копировании коллекции, сравнения коллекции, нахождения максимального и минимального элементов коллекции, а также методы получения специфический модификаций коллекций известных типов (например, можно получить потокобезопасную коллекции or неизменяемую коллекцию с одним элементом).

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