← Назад к вопросам

Приведи пример делегирования

1.0 Junior🔥 81 комментариев
#Kotlin основы#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пример делегирования (Delegation Pattern) в Android/Kotlin

Делегирование — это шаблон проектирования, при котором один объект передаёт часть своей ответственности другому объекту. В отличие от наследования, делегирование использует композицию, что делает код более гибким и соответствует принципу "предпочитайте композицию наследованию".

Ключевые преимущества делегирования:

  • Избегание проблем хрупкого базового класса (fragile base class problem)
  • Возможность динамической смены поведения во время выполнения
  • Более чистая архитектура с разделением ответственности
  • Поддержка принципа единственной ответственности (Single Responsibility Principle)

Практический пример делегирования в Android

Рассмотрим реальный сценарий: нам нужно создать делегирование для обработки кликов в RecyclerView, чтобы отделить логику обработки кликов от адаптера.

1. Создаём интерфейс делегата

// Интерфейс, определяющий контракт для обработки кликов
interface ItemClickDelegate<T> {
    fun onItemClick(item: T, position: Int)
    fun onItemLongClick(item: T, position: Int): Boolean
}

2. Реализуем конкретный делегат

// Конкретная реализация делегата для обработки кликов по пользователям
class UserClickDelegate(
    private val context: Context,
    private val onUserSelected: (User) -> Unit
) : ItemClickDelegate<User> {
    
    override fun onItemClick(item: User, position: Int) {
        // Делегируем обработку клика
        Toast.makeText(context, "Clicked: ${item.name}", Toast.LENGTH_SHORT).show()
        onUserSelected(item)
        
        // Можно добавить аналитику, навигацию и другую логику
        AnalyticsTracker.trackUserClick(item.id)
    }
    
    override fun onItemLongClick(item: User, position: Int): Boolean {
        // Делегируем обработку долгого клика
        showUserOptionsDialog(item)
        return true
    }
    
    private fun showUserOptionsDialog(user: User) {
        // Логика показа диалога
    }
}

###系统3. Используем делегирование в адаптере RecyclerView

class UserAdapter(
    private val users: List<User>,
    // Внедряем делегат через композицию (не наследование!)
    private val clickDelegate: ItemClickDelegate<User>
) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
    
    class UserViewHolder(
        itemView: View,
        private val delegate: ItemClickDelegate<User>
    ) : RecyclerView.ViewHolder(itemView) {
        
        private val nameTextView: TextView = itemView.findViewById(R.id.tv_name)
        private val emailTextView: TextView = itemView.findViewById(R.id.tv_email)
        
        fun bind(user: User) {
            nameTextView.text = user.name
            emailTextView.text = user.email
            
            // Делегируем обработку кликов
            itemView.setOnClickListener {
                delegate.onItemClick(user, adapterPosition)
            }
            
            itemView.setOnLongClickListener {
                delegate.onItemLongClick(user, adapterPosition)
            }
        }
    }
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_user, parent, false)
        return UserViewHolder(view, clickDelegate)
    }
    
    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.bind(users[position])
    }
    
    override fun getItemCount() = users.size
}

4. Пример использования в Activity/Fragment

class UserListFragment : Fragment() {
    
    private lateinit var adapter: UserAdapter
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        val recyclerView: RecyclerView = view.findViewById(R.id.recycler_view)
        
        // Создаём делегат с конкретной логикой
        val clickDelegate = UserClickDelegate(requireContext()) { user ->
            // Действие при выборе пользователя
            navigateToUserDetails(user)
        }
        
        // Передаём делегат в адаптер
        adapter = UserAdapter(getUsers(), clickDelegate)
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(requireContext())
    }
    
    private fun navigateToUserDetails(user: User) {
        // Навигация к деталям пользователя
    }
    
    private fun getUsers(): List<User> {
        return listOf(
            User(1, "Анна", "anna@example.com"),
            User(2, "Иван", "ivan@example.com"),
            User(3, "Мария", "maria@example.com")
        )
    }
}

Вариации делегирования в Kotlin

Использование встроенной поддержки делегирования в Kotlin

// Пример с property delegation
class UserRepository {
    // Делегируем кэширование свойству
    val cachedUsers: List<User> by lazy {
        loadUsersFromDatabase()
    }
    
    // Делегируем логирование observable property
    var lastUpdated: Long by Delegates.observable(System.currentTimeMillis()) { 
        property, oldValue, newValue ->
        Log.d("UserRepository", "Last updated changed from $oldValue to $newValue")
    }
    
    private fun loadUsersFromDatabase(): List<User> {
        // Загрузка из БД
        return emptyList()
    }
}

Делегирование с помощью by в Kotlin

// Интерфейс для загрузки данных
interface DataLoader {
    fun loadData(): String
}

// Реальная реализация
class NetworkDataLoader : DataLoader {
    override fun loadData(): String {
        return "Data from network"
    }
}

// Класс, который делегирует вызовы
class CachedDataLoader(
    private val realLoader: DataLoader
) : DataLoader by realLoader {
    // Мы можем переопределить только нужные методы
    private var cache: String? = null
    
    override fun loadData(): String {
        if (cache == null) {
            cache = realLoader.loadData()
        }
        return cache!!
    }
    
    // И добавить новые методы
    fun clearCache() {
        cache = null
    }
}

Вывод

Делегирование в Android разработке позволяет:

  1. Разделять ответственность между компонентами
  2. Упрощать тестирование — делегаты можно тестировать изолированно
  3. Повышать переиспользуемость кода
  4. Соблюдать принципы SOLID, особенно принцип открытости/закрытости
  5. Уменьшать связность между компонентами

В примере выше мы видим, как делегирование обработки кликов позволяет:

  • Отделить бизнес-логику от UI-логики
  • Легко менять поведение при кликах без изменения адаптера
  • Переиспользовать логику обработки кликов в разных частях приложения
  • Упрощать поддержку и расширение функциональности