Sobes.tech
Middle

Onde utilizou genéricos na sua experiência de desenvolvimento?

sobes.tech IA

Resposta da IA

Utilizou genéricos:

  • Para implementar coleções seguras em termos de tipos. Por exemplo, ArrayList<MyObject> em vez de ArrayList bruto, o que previne erros em tempo de execução relacionados com a conversão de tipos.
    // Abordagem não segura em termos de tipos (tipo bruto)
    List list = new ArrayList();
    list.add("String");
    list.add(123); // Adiciona um int
    
    // Abordagem segura com genéricos
    List<String> stringList = new ArrayList<>();
    stringList.add("String");
    // stringList.add(123); // O compilador irá gerar erro
    
  • Para criar adaptadores universais para RecyclerView. Permite reutilizar a lógica do adaptador para diferentes tipos de dados.
    // Exemplo de ViewHolder universal
    class GenericViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(item: T) {
            // Lógica de ligação de dados dependendo do tipo T
        }
    }
    
    // Exemplo de adaptador universal
    class GenericAdapter<T>(private val items: List<T>) : RecyclerView.Adapter<GenericViewHolder<T>>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GenericViewHolder<T> {
            // Criação do ViewHolder
        }
    
        override fun onBindViewHolder(holder: GenericViewHolder<T>, position: Int) {
            holder.bind(items[position])
        }
    
        override fun getItemCount() = items.size
    }
    
  • Para a criação de fábricas de objetos. Para obter um tipo específico de objeto sem conversão explícita.
    interface Factory<T> {
        T create();
    }
    
    class StringFactory implements Factory<String> {
        @Override
        public String create() {
            return "Nova string";
        }
    }
    
    class IntegerFactory implements Factory<Integer> {
        @Override
        public Integer create() {
            return 100;
        }
    }
    
    Factory<String> stringFactory = new StringFactory();
    String myString = stringFactory.create(); // Obtem um String sem conversão
    
  • Para restringir tipos em métodos e classes. Uso de genéricos restritos (<T extends MyInterface> ou <T super MyClass>) para garantir que o tipo genérico implemente uma interface específica ou herde de uma classe.
    // Método que aceita uma lista de elementos que implementam Serializable
    public <T extends Serializable> void saveObjectList(List<T> list) {
        // Lógica de salvamento
    }
    
  • Em componentes arquiteturais. Por exemplo, ao trabalhar com LiveData ou ViewModel, os genéricos são frequentemente usados para definir o tipo de dados que eles gerenciam.
    // LiveData para uma lista de objetos de um tipo definido
    val myData: LiveData<List<MyItem>> = // inicialização
    
    // ViewModel com dados de um tipo definido
    class MyViewModel : ViewModel() {
        val data: MutableLiveData<MyStateType> by lazy {
            MutableLiveData<MyStateType>()
        }
    }
    
  • No desenvolvimento de clientes de rede. Para a desserialização automática de respostas do servidor em objetos de um tipo específico.
    // Exemplo de serviço Retrofit com genérico na resposta
    interface ApiService {
        @GET("users")
        Call<List<User>> getUsers();
    
        @GET("products/{id}")
        Call<Product> getProduct(@Path("id") String productId);
    }
    

Genéricos melhoraram significativamente a segurança de tipos, legibilidade e reutilização de código.