lichMax
Level 40
Санкт-Петербург

Level 37

Published in the Random EN group
Hello. Again, I did not find answers to these questions. Decided to post the answers that I compiled for myself. Level 37Here are the questions: Interview questions:
  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 is the Arrays class needed?
  10. Why is the Collections class needed?
Here are my answers: My answers:
  1. Design patterns are well-established solutions to the most common problems that arise in the design and development of programs or parts of them.

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

  3. When it is necessary that only one instance of a certain class exists in the program, then 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()the modifier to the method synchronized. But this will not be the best solution (but the easiest). A much better solution is to write the method getInstancelike this (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 of these objects must have a common ancestor (or one common implemented 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 Object3are inherited from class CommonClass.

  5. A pattern Abstract Factoryis also a generative design pattern. According to this pattern, some abstract factory is created that serves as a template for several concrete factories. An example can be given:

    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 the pattern is implemented 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 you would expect the original class to be used. This differs from the implementation of the pattern Adapterin that in this case one interface is used (the same one that the original class has). The pattern Adapteruses two interfaces, and the class that wraps an instance of the original class implements a completely different interface than the interface of the original class.

  7. A pattern Proxyis a structural design pattern. It is needed in order to control access to some object. To do this, a class is written as a "wrapper", that is, a source 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 source object. Implementing the same interface as the original object allows you to replace the original object with a proxy object. It 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 collection object that allows you to sequentially iterate over the elements of this collection. This object must implement the interface Iterator<E>, either 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 if 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

    The interface ListIterator<E>contains the following methods:

    • boolean hasNext()- checks if there is another element in the collection (following the current one)

    • E next()- returns the next element of the collection (and moves the internal iterator cursor to the next element)

    • int nextIndex()- returns the index of the next element

    • void set(E e)— sets the value of the current element void add(E e). Adds an element to the end of the list.

    • boolean hasPrevious()- checks if there is some element in the collection before the given element

    • E previous()- returns the current element of the collection and moves the cursor to the previous element of the collection

    • int previousIndex- returns the index of the previous element of the collection

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

    • void add(E e)- adds an element e after the current element of the collection

  9. A class Arraysis a utility class designed for a variety of array manipulations. This class has methods for turning an array into a list, searching through an array, copying an array, comparing arrays, getting an array hashcode, representing an array as a string, etc.

  10. The class Collectionsis a utility class for working with collections. This class has methods for adding elements to a collection, filling a collection with elements, searching through a collection, copying a collection, comparing a collection, finding the maximum and minimum elements of a collection, as well as methods for obtaining specific modifications of collections of known types (for example, you can get a thread-safe collection or an immutable collection with one element).

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