Пользователь пока ничего не рассказал о себе

Достижения

Все достижения (1)

Наибольший вклад в теги

Все теги (30)

Лучшие ответы пользователя

Все ответы (33)
  • Книги по сетевому программированию на Java на русском языке?

    @terminator-light
    1. Java Network Programming, by Elliotte Rusty Harold (O'Reilly)
    2. Java Network Programming, by Merlin and Conrad Hughes, Michael Shoffner, and Maria Winslow (Manning, an imprint of Prentice-Hall)
    3. Advanced Java Networking, by Prashant Sridharan (Prentice-Hall)
    4. Java Networking and Communications, by Todd Courtois (Prentice-Hall)
    5. Java Networking and AWT API SuperBible, by Nataraj Nagaratnam, Brian Maso, and Arvind Srinivasan (Waite)

    Java network programming books: A comparative review
    Ответ написан
  • Kotlin + Android studio?

    @terminator-light
    Зачем переделывать, если Kotlin интероперабелен с Java? Их вполне можно юзать в одном проекте вместе.
    Перевести весь проект на Kotlin - это уже зависит от предпочтений, вкуса, времени самого программиста/бизнеса
    Ответ написан
  • Android development: каким должен быть масштабируемый код?

    @terminator-light
    Для того чтобы писать масштабируемый необходимо знание не только паттернов GOF,
    но и архитектурных: MVC, MVP, MVVM, MVI. Важно изучить достоинства и недостатки каждого.
    Во главу угла также стоят принципы SOLID, далее приведу небольшие примеры:
    1. Single Responsibility principle - принцип единственной ответственности. Метод/класс должен выполнять только одну задачу. Например, метод, предназначенный для загрузки данных из сети, не должен заниматься обработкой ошибок.
    Псевдокодом напишу:
    spoiler
    public void loadData(String url){
    	repository.fetchProducts().get(products->{
    		view.showProducts(products);
    	}, throwable ->{
    		if(throwable instanceof IOexception){
    			view.showNoNetwork();
    		}else(throwable instanceof HTTPException){
    			HTTPException exception = (HTTPException)throwable;
    		 	switch(exception.getCode()){
    		 		case 400:
    		 			view.showError(exception.getMessage());
    		 			break;
    		 		case 401:
    		 			view.showUnauthorized();
    		 			break;
    		 			...
    		 	}
    		}
    		...
    	});
    }

    Вместо этого вторую часть нужно выделить в другой метод/класс.
    spoiler
    public void loadData(String url){
    	repository.fetchProducts().get(products-> view.showProducts(products), 
    		throwable -> ErrorUtil.handleError(throwable, view));
    }
    
    public class ErrorUtil{
    	public static void handleError(Throwable throwable, View view){
    		if(throwable instanceof IOexception){
    			view.showNoNetwork();
    		}else(throwable instanceof HTTPException){
    			HTTPException exception = (HTTPException)throwable;
    		 	switch(exception.getCode()){
    		 		case 400:
    		 			view.showError(exception.getMessage());
    		 			break;
    		 		case 401:
    		 			view.showUnauthorized();
    		 			break;
    		 			...
    		 	}
    		}
    		...
    	}
    }


    2. Open/Closed principle - принцип открытости/закрытости. Код должен быть открыт для добавления функциональности, но закрыт для изменения.
    Например, есть такой код для работы с тулбаром. Если экранов будет много с разными тулбарами,
    то постоянно придется добавлять новую ветку case, а значит изменять класс ToolbarManager,
    при этом есть возможность появления ошибки в местах, касающихся и других case-веток
    spoiler
    public class ToolbarManager{
    	public void showToolbar(int type){
    		switch(type){
    			case MAIN:
    				....
    				//огромный кусок кода для показа тулбара для главного экрана
    				....
    				break;
    			case PROFILE:
    				...
    				//огромный кусок кода для показа тулбара для экрана профиля
    				...
    			...
    		}
    	}
    }

    Решение: воспользоваться одним из принципов ООП - полиморфизмом. Теперь, если понадобится добавить
    новый экран, нужно будет просто реализовать интерфейс, и это не будет касаться кода других экранов.
    spoiler
    public interface ToolbarManager{
    	void showToolbar();
    }
    
    public class MainToolbarManager implements ToolbarManager{
    	public void showToolbar(){
    		....
    		//огромный кусок кода для показа тулбара для главного экрана
    		....
    	}
    }
    
    public class ProfileToolbarManager implements ToolbarManager{
    	public void showToolbar(){
    		....
    		//огромный кусок кода для показа тулбара для экрана профиля
    		....
    	}
    }

    3. Liskov Substitution principle - принцип подстановки Барбары Лисков гласит: Если класс B - это подтип A, то мы должны иметь
    возможность заменить A на B, не нарушая поведение программы.
    Для данного принципа не могу придумать пример, связанный с Android, но мне понравился этот пример,
    взятый из этого сайта https://www.baeldung.com/solid-principles
    spoiler
    public interface Car {
        void turnOnEngine(); //запустить двигатель
        void accelerate(); //подать газ
    }
    
    public class MotorCar implements Car {
     
        private Engine engine;
     
        public void turnOnEngine() {
            //вруби мотор!
            engine.on();
        }
     
        public void accelerate() {
            //поезжай вперед!
            engine.powerOn(1000);
        }
    }

    Наш класс удовлетворяет интерфейсу, у нас есть машина, которая имеет свой мотор,
    и мы можем ускориться. Но мы живем в 2019 году, а Илон Маск старательный человек. Мы живем в эпоху электрокаров:
    spoiler
    public class ElectricCar implements Car {
     
        public void turnOnEngine() {
            throw new AssertionError("А у меня вообще нет двигателя");
        }
     
        public void accelerate() {
            //ускорение сумасшедшее!
        }
    }

    Выбрасывая машину без двигателя в общую кучу, мы меняем поведение нашей программы.
    Это грубое нарушение принципа подстановки Барбары Лисков. Решить данную проблему будет непросто.
    Но одним из решений было бы разбиение нашей модели на мелкие интерфейсы, которые учитывают состояние без двигателя
    spoiler
    public interface Engineful {
    
        void turnOnEngine();
    }
    public interface Acceleratable {
        void accelerate();
    }
    public class MotorCar implements Engineful, Acceleratable {
     
        private Engine engine;
     
        public void turnOnEngine() {
            //вруби мотор!
            engine.on();
        }
     
        public void accelerate() {
            //поезжай вперед!
            engine.powerOn(1000);
        }
    }
    public class ElectricCar implements Acceleratable {
        public void accelerate() {
            //ускорение сумасшедшее!
        }
    }


    4. Interface segregation principle - прин­цип раз­де­ле­ния интер­фейса.
    Создавайте гранённые мелкие интерфейсы. Клиентский код не должен зависеть от функций интерфейса, которые он
    не будет использовать. Возьмем пример из Android SDK, убрал некоторые детали для простоты:
    spoiler
    public interface TextWatcher{
        public void beforeTextChanged(CharSequence s, int start, int count, int after);
        public void onTextChanged(CharSequence s, int start, int before, int count);
        public void afterTextChanged(Editable s);
    }


    И клиентский код:
    spoiler
    editText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
        }
    
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
    
        }
    
        @Override
        public void afterTextChanged(Editable s) {
        	//метод, который нам нужен
        	//какие-то полезные действия
        }
    });

    Как видно остальные методы нам не нужны, и мы их не используем. Здесь явное нарушение ISP,
    т.к. интерфейс навязывает использование других методов

    5. Dependency inversion principle - принцип инверсии зависимостей.
    Высокоуровневые модули не должны зависеть от низкоуровневых.
    Абстракции не должны зависеть от деталей. Но детали зависят от абстракций.
    Пример: у нас есть класс Repository, отвечающий за получение данных из разных источников.
    Проблема в том, что объекты жестко заданы в конструкторе. И мы не имеем возможности
    поменять реализацию AppDataBase на FakeDataBase для тестов.
    spoiler
    public class Repository{
    	private final NetworkManager networkManager;
    	private final AppDataBase appDataBase;
    	public Repository(){
    		this.networkManager = new NetworkManager();
    		this.AppDataBase = new AppDataBase();
    	}
    }


    Поэтому нам следует как-то развязать жесткую связь, выделив интерфейсы.
    spoiler
    public interface RemoteDataSource{}
    public interface LocalDataSource{}
    public class NetworkManager implements RemoteDataSource{}
    public class AppDataBase implements LocalDataSource{}
    
    public class Repository{
    	private final RemoteDataSource remoteDataSource;
    	private final LocalDataSource localDataSource;
    	public Repository(RemoteDataSource remoteDataSource, LocalDataSource localDataSource){
    		this.remoteDataSource = remoteDataSource;
    		this.localDataSource = localDataSource;
    	}
    }


    А теперь мы можем тестовую реализацию источников:
    public class FakeNetworkManager implements RemoteDataSource{}
    public class FakeAppDataBase implements LocalDataSource{}

    и вызов:
    Repository repository = new Repository(new FakeNetworkManager(), new FakeAppDataBase());


    У Мартина Фаулера есть хорошая книга Рефакторинг: Улучшение существующего кода и Р.Мартина Чистый код
    Ответ написан
  • Как сделать закругление кнопок?

    @terminator-light
    <style name="AppTheme" parent="YourTheme">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <item name="materialButtonStyle">@style/systemButtonStyle</item> <!-- если используете MaterialComponents -->
            <item name="buttonStyle">@style/systemButtonStyle</item> <!-- если используете AppCompat  -->
     </style>
    
    <style name="systemButtonStyle" parent="Widget.MaterialComponents.Button">
          <item name="android:background">@drawable/roundedbutton</item>
    </style>

    drawable/roundedbutton.xml
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" 
    android:shape="rectangle">
        <solid android:color="#ff0000" />
        <corners android:radius="8dp"/>
    </shape>
    Ответ написан
  • С помощью цикла вывести на экран все простые числа от 1 до 100 как почему выходит true?

    @terminator-light
    for(int i = 2; i < 100; ++i){
    	int count = 0;
    	for(int j = 2; j <=i && count < 2;++j){
    		if(i%j==0){
    			++count;
    		}
    	}
    	if(count<2)
    	   System.out.println(i);
    }
    Ответ написан

Лучшие вопросы пользователя

Все вопросы (25)