Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar
translation

Esta é uma postagem traduzida por IA.

제이온

[Effective Java] Item 1: Considere métodos de fábrica estáticos em vez de construtores

  • Idioma de escrita: Coreana
  • País de referência: Todos os países country-flag

Selecionar idioma

  • Português
  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

Texto resumido pela IA durumis

  • Os métodos de fábrica estáticos são uma maneira de criar instâncias de uma classe em vez de construtores, o que permite nomear as instâncias, melhorar o desempenho armazenando em cache objetos de criação dispendiosa e retornar diferentes tipos de subtipos de objetos conforme necessário.
  • Especialmente antes do Java 8, os métodos estáticos não podiam ser declarados em interfaces, então uma classe de companheiro foi criada para definir métodos de fábrica estáticos, mas depois do Java 8, métodos estáticos podem ser adicionados diretamente a uma interface, tornando desnecessário definir classes de companheiro separadas.
  • Ao usar métodos de fábrica estáticos, a composição é incentivada em vez da herança, e essa restrição pode ser uma vantagem para criar tipos imutáveis, mas como eles não são tão evidentes quanto os construtores na documentação da API, os desenvolvedores devem aliviar o problema fornecendo boa documentação da API e definindo nomes de métodos de acordo com convenções amplamente conhecidas.

Visão geral

O meio tradicional de obter instâncias de classe é por meio de construtores públicos.


public class Member {

    private String name;

    private int age;

    private String hobby;

    private MemberStatus memberStatus;

    public Member(String name, int age, String hobby, MemberStatus memberStatus) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
        this.memberStatus = memberStatus;
    }
}

public enum MemberStatus {

    ADVANCED,
    INTERMEDIATE,
    BASIC;


Normalmente, construtores públicos são suficientes, mas fornecer métodos estáticos de fábrica (static factory method) além dos construtores frequentemente torna mais fácil para os usuários criar instâncias como desejado.


Um exemplo típico de método de fábrica estático é o método valueOf() de Boolean.


public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;


O método acima recebe um valor booleano do tipo primitivo e retorna um objeto Boolean.


Vantagens do método de fábrica estático

Pode ter um nome

Os parâmetros passados para o construtor e o próprio construtor não conseguem descrever adequadamente as características do objeto que será retornado. Por exemplo, é difícil determinar quais características um membro tem apenas olhando para o construtor principal da classe Member (name, age, hobby, memberStatus).


Além disso, um construtor pode ser criado com uma assinatura, mas métodos de fábrica estáticos podem ter nomes, então uma assinatura pode ser usada para criar vários métodos de fábrica estáticos para retornar instâncias.


public class Member {

    private String name;

    private int age;

    private String hobby;

    private MemberStatus memberStatus;

    public Member(String name, int age, String hobby, MemberStatus memberStatus) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
        this.memberStatus = memberStatus;
    }

    public static Member basicMember(String name, int age, String hobby) {
        return new Member(name, age, hobby, MemberStatus.BASIC);
    }

    public static Member intermediateMember(String name, int age, String hobby) {
        return new Member(name, age, hobby, MemberStatus.INTERMEDIATE);
    }

    public static Member advancedMember(String name, int age, String hobby) {
        return new Member(name, age, hobby, MemberStatus.ADVANCED);
    }


Como acima, criar vários métodos de fábrica estáticos com a mesma assinatura em vez de usar MemberStatus no construtor permite que os usuários criem instâncias Member com habilidades específicas sem confusão.

Se olharmos para as bibliotecas definidas no JDK, veremos o método de fábrica estático probablePrime() de BigInteger.


public static BigInteger probablePrime(int bitLength, Random rnd) {
    if (bitLength < 2)
        throw new ArithmeticException("bitLength < 2");

    return (bitLength < SMALL_PRIME_THRESHOLD ?
            smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
            largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));


Ao comparar o construtor geral de BigInteger com o método de fábrica estático probablePrime(), o último descreve melhor a frase que retorna um BigInteger que é um número primo.


Não precisa criar uma nova instância a cada chamada

public static Boolean valueOf(boolean b) {
    return (b ? Boolean.TRUE : Boolean.FALSE);


O método valueOf() de Boolean coloca em cache as instâncias e as retorna. Este recurso pode melhorar significativamente o desempenho em cenários onde objetos caros são solicitados com frequência.Flyweight Patterné uma técnica semelhante.


As classes que usam métodos de fábrica estáticos para retornar a mesma instância para solicitações repetidas são chamadas de classes de controle de instância, pois podem controlar o ciclo de vida da instância. Ao controlar instâncias, você pode criar uma classe Singleton ou uma classe que não pode ser instanciada. Além disso, você pode garantir que uma classe de valor imutável tenha apenas uma instância.

O controle de instâncias é a base do padrão Flyweight, e os tipos de enumeração garantem que apenas uma instância é criada.


Exemplo

Na Minecraft, você precisa plantar árvores. Se cada objeto de árvore for criado novamente, isso pode levar a um estouro de memória.

Portanto, você pode salvar objetos de árvores vermelhas e verdes e apenas retornar suas localizações. É claro que a cor pode ser mais do que essas duas, então seria mais eficiente salvar árvores em uma estrutura de dados como um mapa de acordo com sua cor.


public class Tree {

    // Uma árvore tem as seguintes três informações.
    private String color;
    private int x;
    private int y;

    // Um construtor é criado apenas para a cor.
    public Tree(String color) {
        this.color = color;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    // Quando uma árvore é plantada
    public void install(){
        System.out.println("x:"+x+" y:"+y+" A árvore "+color+" foi instalada!");
    }
}

public class TreeFactory {
    // Gerenciar árvores criadas usando a estrutura de dados HashMap.
    public static final Map treeMap = new HashMap<>();
    
   
    public static Tree getTree(String treeColor){
        // Verifica se há uma árvore da cor fornecida no mapa. Se houver, fornece esse objeto.
        Tree tree = (Tree)treeMap.get(treeColor); 

       // Se não houver uma árvore da mesma cor no mapa, crie um novo objeto e forneça-o.
        if(tree == null){
            tree = new Tree(treeColor);
            treeMap.put(treeColor, tree);
            System.out.println("Novo objeto criado");
        }

        return tree;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.println("Digite a cor que você deseja :)");
        for(int i=0;i<10;i++){
            // Obter a cor da árvore
            String input = scanner.nextLine();
            // Obter uma árvore da fábrica
            Tree tree = (Tree)TreeFactory.getTree(input);
            // Definir x, y da árvore e
            tree.setX((int) (Math.random()*100));
            tree.setY((int) (Math.random()*100));
            // Instale a árvore
            tree.install();
        }
    }


Diferença com o padrão Singleton

O padrão Singleton permite que apenas uma árvore seja criada na classe Tree. Portanto, se você usar o padrão Singleton, você terá que mudar a cor do único objeto criado. Ou seja, o padrão Singleton permite apenas uma, independentemente do tipo.


Casos de uso

O Flyweight Pattern é usado no String Constant Pool do Java.


Você pode retornar um objeto do tipo de subtipo

Se você já usou o método asList() da classe de utilitários Arrays, você pode entender essa vantagem.


public static  List asList(T... a) [
    return new ArrayList<>(a);


Ele envolve o valor em um ArrayList, que é uma implementação da subclasse de List, mas o usuário não precisa saber sobre essa implementação. Em outras palavras, a flexibilidade de poder escolher a classe do objeto retornado permite que os desenvolvedores mantenham uma API pequena sem expor a implementação.


Histórias relacionadas a métodos estáticos de interface Java

Antes do Java 8, métodos estáticos não podiam ser declarados em interfaces, então uma classe companheira que não podia ser instanciada chamada "Types" era criada para definir métodos dentro dela, se necessário, um método estático que retornasse uma interface chamada "Type".


Um exemplo clássico é o Java Collection Framework (JCF), que possui 45 implementações de utilitários, a maioria dos quais é obtida por meio de métodos de fábrica estáticos na classe companheira java.util.Collections. Em particular, algumas dessas implementações não são públicas e só podem ser instanciadas por meio de métodos de fábrica estáticos. (Obviamente, essas implementações não podem ser herdadas).


Além disso, a API pode ser mantida muito menor, pois as 45 implementações não são expostas.


// Interface e classe companheira


No entanto, a partir do Java 8, os métodos estáticos podem ser adicionados diretamente às interfaces, então não há necessidade de definir classes companheiras separadamente.


Você pode retornar objetos de classes diferentes dependendo dos parâmetros de entrada.

Além de simplesmente retornar subtipos, você pode retornar subtipos diferentes dependendo do valor do parâmetro. Por exemplo, se você quiser retornar MemberStatus diferente dependendo da pontuação, você pode criar um método de fábrica estático e colocar lógica de comparação nele, como mostrado abaixo.


public enum MemberStatus {

    ADVANCED(80, 100),
    INTERMEDIATE(50, 79),
    BASIC(0, 49);

    private final int minScore;
    private final int maxScore;

    MemberStatus(int minScore, int maxScore) {
        this.minScore = minScore;
        this.maxScore = maxScore;
    }

    public static MemberStatus of(int score) {
        return Arrays.stream(values())
                .filter(decideMemberStatus(score))
                .findAny()
                .orElseThrow(() -> new NoSuchElementException("Não há um objeto MemberStatus correspondente."));
    }

    private static Predicate decideMemberStatus(int score) {
        return element -> element.minScore <= score && element.maxScore >= score;
    }
}

@DisplayName("Teste MemberStatus")
class MemberStatusTest {

    @ParameterizedTest
    @CsvSource(value = {"0:BASIC", "30:BASIC", "50:INTERMEDIATE", "70:INTERMEDIATE", "80:ADVANCED", "100:ADVANCED"}, delimiter = ':')
    @DisplayName("Retorna MemberStatus diferente dependendo da pontuação.")
    void of(int input, MemberStatus expected) {
        assertThat(MemberStatus.of(input)).isEqualTo(expected);
    }


A classe do objeto a ser retornado não precisa existir no momento em que o método de fábrica estático é escrito.

Na frase acima,classe de objetoé o nosso arquivo de classe.

Observe que Class é um objeto Class alocado na área de heap quando o carregador de classes carrega uma classe. Este objeto Class contém vários metadados da classe que escrevemos.


package algorithm.dataStructure;

public abstract class StaticFactoryMethodType {

    public abstract void getName();

    public static StaticFactoryMethodType getNewInstance() {
        StaticFactoryMethodType temp = null;
        try {
            Class childClass = Class.forName("algorithm.dataStructure.StaticFactoryMethodTypeChild"); // Reflexão
            temp = (StaticFactoryMethodType) childClass.newInstance(); // Reflexão

        } catch (ClassNotFoundException e) {
           System.out.println("Classe não encontrada.");
        } catch (InstantiationException  e) {
            System.out.println("Não pode ser carregado na memória.");
        } catch (IllegalAccessException  e) {
            System.out.println("Erro de acesso ao arquivo de classe.");
        }

        return temp;
    }


O código acima mostra como um objeto Class é criado com base no local da implementação da interface e a implementação real é inicializada usando a técnica de reflexão. Neste momento,quando o método de fábrica estático é escritoa classe StaticFactoryMethodTypeChild não precisa existir.


Se a implementação não existir no caminho algorithm.dataStructure.StaticFactoryMethodTypeChild quando o método de fábrica estático for usado, um erro ocorrerá, mas não haverá problema quando o método de fábrica estático for escrito, então é flexível.


public interface Test {

    int sum(int a, int b);

    // Test é uma interface e não há problema na hora de escrever o método de fábrica estático, mesmo que não haja implementação.
    static Test create() {
        return null;
    }
}

public class Main {

    public static void main(String[] args) {
        Test test = Test.create();
        System.out.println(test.sum(1, 2)); // NPE ocorre
    }


Você pode obter a mesma flexibilidade sem usar a reflexão. O método create() do método de fábrica estático de Test mostra que não há problema na hora de escrever, mesmo que não haja implementação. Claro, um NPE ocorrerá quando você realmente o usar, então você precisa fornecer a implementação mais tarde.


Essa flexibilidade é a base para a criação de estruturas de provedores de serviços, como o JDBC. Em uma estrutura de provedor de serviços, o provedor é a implementação do serviço e a estrutura controla a entrega dessas implementações ao cliente, separando o cliente da implementação. (DIP)


  • Componentes da estrutura do provedor de serviços
    • Interface de serviço
      • Define o comportamento da implementação.
      • JDBC Connection
    • API de registro de provedor
      • O provedor registra a implementação.
      • JDBC DriverManager.registerDriver()
    • API de acesso ao serviço
      • Usado quando o cliente obtém a instância do serviço, e se nenhuma condição for especificada, a implementação padrão ou a implementação compatível será retornada alternadamente.
      • Aplica-se a métodos de fábrica estáticos.
      • JDBC DriverManager.getConnection()
    • (Opcional) Interface do provedor de serviços
      • Se este não existir, a reflexão deve ser usada para instanciar cada implementação.
      • JDBC Driver


O padrão de estrutura de provedor de serviços tem muitas variações, incluindo o padrão de ponte, estrutura de injeção de dependência, etc.


Típico Exemplo JDBC

Class.forName("oracle.jdbc.driver.OracleDriver"); 
Connection connection = null; 
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORA92", "root", "root"); 


O JDBC é normalmente escrito como acima. OracleDriver, que é uma das implementações do Driver, é registrado por meio de Class.forName(), e uma das implementações de Connection, Connection para OracleDriver, é obtida por meio de DriverManager.getConnection().


Aqui, Connection é a interface de serviço, DriverManager.getConnection() é a API de acesso ao serviço e Driver é a interface do provedor de serviço. No entanto, DriverManager.registerDriver(), que é a API de registro do provedor, não é usada. No entanto, podemos registrar OracleDriver, que é a implementação do Driver, usando apenas Class.forName(). Como isso é possível?


Como Class.forName() funciona

Este método solicita ao JVM para carregar essa classe passando o nome do arquivo de classe físico como argumento. Então, o carregador de classes armazena os metadados da classe na área de método e, ao mesmo tempo, aloca um objeto Class na área de heap. Além disso, quando o carregamento da classe termina,campos estáticos e blocos estáticos são inicializados, e a API de registro do provedor é usada aqui.


public class OracleDriver implements Driver {

    static {
        defaultDriver = null;
        Timestamp timestamp = Timestamp.valueOf("2000-01-01 00:00:00.0");
        try {
            if (defaultDriver == null) {
                defaultDriver = new OracleDriver();
                DriverManager.registerDriver(defaultDriver); // Registro de OracleDriver
            }
        } catch (RuntimeException runtimeexception) {
        } catch (SQLException sqlexception) {
        }
    }

    ...


Na verdade, ao olhar para o OracleDriver, podemos ver que o OracleDriver é registrado usando DriverManager.registerDriver() no bloco estático.


Analisando a classe DriverManager

public class DriverManager {

    private DriverManager() {
    }

    private static final Map drivers = new ConcurrentHashMap();
    public static final String DEFAULT_DRIVER_NAME = "default";

    public static void registerDefaultPrivider(Driver d) {
        System.out.println("Registro de Driver");
        registerDriver(DEFAULT_DRIVER_NAME, d);
    }

    public static void registerDriver(String name, Driver d) {
        drivers.put(name, d);
    }

    public static Connection getConnection() {
        return getConnection(DEFAULT_DRIVER_NAME);
    }

    public static Connection getConnection(String name) {
        Driver d = drivers.get(name);
        if (d == null) throw new IllegalArgumentException();
        return d.getConnection();
    }


A classe DriverManager é realmente muito mais complexa, mas se você resumir apenas o essencial, será semelhante ao acima. Como explicado anteriormente, OracleDriver é registrado chamando registerDriver() no bloco estático de OracleDriver, e os usuários podem obter a implementação de Connection chamando getConnection().


Se você olhar mais de perto para o método getConnetion() da API de acesso do usuário, você verá que ele obtém Connection da interface Driver. Se a interface do provedor de serviços Driver não existir, você pode usar a reflexão, como Class.forName(), para retornar a implementação de Connection desejada. Neste caso,a implementação de Connection não precisa existir quando o método de fábrica estático é escrito.


Em vez disso, usamos a interface Driver e podemos facilmente obter a implementação de Connection que corresponde a ela, registrando dinamicamente a implementação de Driver.


Por falar nisso, analisei o código real do JDK do método getConnection() de DriverManager, mas se você não estiver interessado, pode ignorá-lo.


@CallerSensitive
public static Connection getConnection(String url,
    String user, String password) throws SQLException {
    java.util.Properties info = new java.util.Properties();

    if (user != null) {
        info.put("user", user);
    }
    if (password != null) {
        info.put("password", password);
    }

    return (getConnection(url, info, Reflection.getCallerClass()));


Primeiro, o método estático público getConnection() é chamado, e url, Properties e CallerClass são passados como argumentos para o método estático privado getConnection(). Neste momento, Reflection.getCallerClass() obtém a classe que chamou o método estático público getConnection(). Se a classe Car chamar getConnection(), um objeto Class pode ser obtido por Reflection.getCallerClass().


private static Connection getConnection(String url, java.util.Properties info, Class caller) throws SQLException {
    ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
    synchronized(DriverManager.class) {
        if (callerCL == null) {
            callerCL = Thread.currentThread().getContextClassLoader();
        }
    }

    if(url == null) {
        throw new SQLException("O url não pode ser nulo", "08001");
    }

    SQLException reason = null;
    for(DriverInfo aDriver : registeredDrivers) {
        if(isDriverAllowed(aDriver.driver, callerCL)) {
            try {
                Connection con = aDriver.driver.connect(url, info);
                if (con != null) {
                    return (con);
                }
            } catch (SQLException ex) {
                if (reason == null) {
                    reason = ex;
                }
            }
        }
    }

    if (reason != null)    {
        throw reason;
    }
    throw new SQLException("Nenhum driver adequado encontrado para "+ url, "08001");


callerCL é um objeto carregador de classes e é criado pelo carregador de classes do caller ou da thread atual. Em seguida, ele percorre um a um aDriver na lista de drivers registrados registeredDrivers no aplicativo atual. E se esse Driver for true por isDriverAllowed(), ele obtém um objeto Connection desse Driver e retorna. isDriverAllowed() é responsável por verificar se aDriver existe no caller.


Vantagens da estrutura JDBC

O ponto principal da estrutura JDBC é que o Driver, a interface Connection e as classes de implementação que realmente implementam essas interfaces são fornecidas completamente separadamente. Criar um modelo usando interfaces e depois criar classes de implementação que se encaixam nesse modelo é muito flexível.


Portanto, mesmo que um novo DBMS seja lançado, o fornecedor pode fornecer implementações de Driver e Connection, permitindo que desenvolvedores que usam Java usem a mesma API que outros drivers de DBMS.


Desvantagens do método de fábrica estático

Se você precisar herdar, precisa de um construtor público ou protegido, então você não pode criar uma subclasse se fornecer apenas um método de fábrica estático.


No entanto, essa restrição pode ser uma vantagem, pois incentiva a composição em vez da herança e essa restrição deve ser mantida para criar um tipo imutável.


Os métodos de fábrica estáticos são difíceis para os programadores encontrarem.

Como não é exposto claramente na descrição da API como um construtor, os desenvolvedores devem minimizar o problema escrevendo documentação de API bem e usando nomes de métodos que sigam convenções amplamente conhecidas.


Convenções de nomenclatura do método de fábrica estático

  • from
    • Recebe um parâmetro e retorna uma instância desse tipo.
    • Date date = Date.from(instant);
  • of
    • Recebe vários parâmetros e retorna uma instância do tipo apropriado.
    • Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOf
    • Uma versão mais detalhada do from e of
    • BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • instance ou getInstance
    • Retorna a instância especificada pelo parâmetro, mas não garante que seja a mesma instância.
    • StackWalker luke = StackWalker.getInstance(options);
  • create ou newInstance
    • Semelhante ao instance ou getInstance, mas garante que uma nova instância é criada e retornada.
    • Object newArray = Array.newInstance(classObject, arraylen);
  • getType
    • Semelhante ao getInstance, mas usado quando o método de fábrica é definido em uma classe diferente da classe a ser criada.
    • FileStore fs = Files.getFileStore(path);
  • newType
    • Semelhante ao newInstance, mas usado quando o método de fábrica é definido em uma classe diferente da classe a ser criada.
    • BufferedReader br = Files.newBufferedReader(path);
  • type
    • Versão concisa de getType e newType
    • List<Complaint> litany = Collections.list(legacyLitany);


Resumo

Os métodos de fábrica estáticos e os construtores públicos têm seus próprios usos, então vamos usá-los adequadamente.


Fonte

제이온
제이온
제이온
제이온
[Effective Java] Item 5: Use dependency injection instead of explicitly specifying resources Se uma classe depender de recursos externos, é melhor não usar singletons e classes de utilitário estáticas. A injeção de dependência pode ser usada para melhorar a flexibilidade, reusabilidade e facilidade de teste da classe, e o padrão de fábrica pode s

28 de abril de 2024

[Effective Java] Item 3. Garanta o Singleton com um construtor privado ou um tipo de enumeração Este artigo apresenta três métodos para implementar o padrão Singleton em Java (membro estático público, método de fábrica estático e tipo de enumeração), e discute os prós e contras de cada método, bem como as precauções a serem tomadas ao serializar. El

27 de abril de 2024

[Effective Java] Item 2: Considere um construtor se você tiver muitos parâmetros Ao criar objetos com muitos parâmetros, o padrão de construtor pode tornar o código mais limpo e legível. Crie um objeto de construtor com parâmetros obrigatórios e use métodos setter para definir parâmetros opcionais e, em seguida, chame o método build()

27 de abril de 2024

[Javascript] Estrutura do Objeto (V8) O Objeto JavaScript no motor V8 é otimizado como uma estrutura dependendo do estado, alternando entre o modo Rápido e o modo Dicionário, que funciona como um mapa hash. O modo Rápido é rápido quando as chaves e valores são quase fixos, mas quando uma nova
곽경직
곽경직
곽경직
곽경직
곽경직

18 de março de 2024

[Não graduado, sobrevivendo como desenvolvedor] 14. Resumo do conteúdo da entrevista técnica frequente para desenvolvedores juniores Guia de preparação para entrevista técnica para desenvolvedores juniores. Área de memória principal, estrutura de dados, RDBMS e NoSQL, orientação de procedimentos e orientação de objetos, sobreposição e sobrecarga, algoritmo de substituição de página, pr
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 de abril de 2024

[Não graduado, sobrevivendo como desenvolvedor] 16. Dicas para criar um portfólio de desenvolvedor júnior Desenvolvedores juniores (especialmente aqueles sem formação em informática) precisam explicar claramente os serviços ou funcionalidades desenvolvidos no seu portfólio, além das tecnologias utilizadas. Por exemplo, em um projeto de "comunidade para candid
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 de abril de 2024

[Metalurgia de Materiais Mestre Prático] Resolução do Exame 39 Este post do blog trata dos conceitos básicos de propriedades mecânicas de materiais, tratamento térmico, métodos de teste e inspeção não destrutiva. Explica vários conceitos e termos, como resistência à tração, dureza, cementação, teste de emissão acústi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi

24 de abril de 2024

Modelagem de Dados Lógica A modelagem de dados lógica é o processo de transformar a modelagem de dados conceitual de acordo com o paradigma de banco de dados relacional, tratando relacionamentos 1:1, 1:N, N:M e garantindo a integridade dos dados por meio da normalização. Ele passa
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

9 de abril de 2024

[Prova prática de mestre em materiais metálicos] Solução da 37ª edição Este material contém informações variadas sobre as propriedades dos materiais metálicos, métodos de teste, tratamento térmico, ligas, etc. Abrange tópicos diversos, como o medidor de transmitância, curva de magnetização, análise microestrutural, teste mic
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi

24 de abril de 2024