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

Ceci est un post traduit par IA.

제이온

[Efficace Java] Item 1. Envisager des méthodes d'usine statiques à la place des constructeurs

Choisir la langue

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

Texte résumé par l'IA durumis

  • Les méthodes d'usine statiques sont une façon de créer des instances d'une classe à la place des constructeurs, ce qui permet de nommer les instances, de mettre en cache les objets dont la création est coûteuse pour améliorer les performances et de renvoyer des objets de sous-types différents si nécessaire.
  • En particulier, avant Java 8, il était impossible de déclarer des méthodes statiques dans les interfaces, il fallait donc créer une classe compagnon pour définir les méthodes d'usine statiques. Depuis Java 8, il est possible d'ajouter directement des méthodes statiques aux interfaces, ce qui élimine le besoin de définir une classe compagnon séparée.
  • L'utilisation de méthodes d'usine statiques encourage la composition plutôt que l'héritage et peut être un avantage pour créer des types immuables car elle impose cette contrainte. Cependant, contrairement aux constructeurs, elles ne sont pas explicites dans la description de l'API, ce qui signifie que les développeurs doivent documenter l'API et choisir des noms de méthodes conformes à des conventions largement reconnues afin d'atténuer le problème.

Vue d'ensemble

Le moyen traditionnel d'obtenir une instance d'une classe est le constructeur public.


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;


En général, les constructeurs publics suffisent, mais il arrive souvent que fournir une méthode d'usine statique (static factory method) en plus du constructeur facilite la création d'instances par l'utilisateur de manière conforme à ses intentions.


Un exemple typique de méthode d'usine statique est la méthode valueOf() de Boolean.


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


Cette méthode prend une valeur booléenne de type primitif et la convertit en objet Boolean, qu'elle renvoie ensuite.


Avantages des méthodes d'usine statiques

Elles peuvent avoir un nom.

Les paramètres transmis au constructeur et le constructeur lui-même ne suffisent pas toujours à décrire correctement les caractéristiques de l'objet qui sera renvoyé. Par exemple, il est difficile de déterminer les caractéristiques d'un Member en regardant uniquement le constructeur principal de la classe Member (name, age, hobby, memberStatus).


De plus, un seul constructeur peut être créé pour une seule signature, tandis qu'une méthode d'usine statique peut avoir un nom. Il est donc possible de créer plusieurs méthodes d'usine statiques ayant la même signature pour renvoyer des instances.


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);
    }


Comme indiqué ci-dessus, la création de plusieurs méthodes d'usine statiques ayant la même signature au lieu de différencier MemberStatus par le constructeur permet à l'utilisateur de créer des instances de Member ayant un niveau de compétence spécifique sans risque de confusion.

Dans les bibliothèques définies par le JDK, on trouve probablePrime(), une méthode d'usine statique 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));


En comparant le constructeur général de BigInteger à probablePrime(), une méthode d'usine statique, il est clair que cette dernière décrit mieux la phrase "renvoie un BigInteger dont la valeur est un nombre premier".


Elles ne doivent pas créer de nouvelle instance à chaque appel.

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


On peut voir que la méthode valueOf() de Boolean met en cache les instances avant de les renvoyer. Cette caractéristique peut améliorer considérablement les performances dans les cas où des objets coûteux à créer sont fréquemment demandés, et peut être considérée comme une technique similaire au modèle Flyweight.


Les classes qui utilisent des méthodes d'usine statiques pour renvoyer le même objet aux demandes répétitives sont appelées classes de contrôle des instances, car elles peuvent contrôler le cycle de vie des instances. Le contrôle des instances permet de créer des classes singleton ou des classes impossibles à instancier. Il permet également de garantir qu'une seule instance existe pour les classes immuables.

Le contrôle des instances est à la base du modèle Flyweight, et les types énumérés garantissent que seule une instance est créée.


Exemple

Dans Minecraft, vous devez planter des arbres. Si chaque objet arbre est créé à nouveau, il y a un risque de dépassement de la mémoire.

Par conséquent, vous pouvez stocker les objets arbre rouge et arbre vert et simplement renvoyer leur position. Bien sûr, comme il peut y avoir plus de deux couleurs, il serait plus efficace de stocker les arbres dans une structure de données comme une Map en fonction de leur couleur.


public class Tree {

    // Un arbre possède les 3 informations suivantes.
    private String color;
    private int x;
    private int y;

    // Constructeur créé uniquement avec la couleur.
    public Tree(String color) {
        this.color = color;
    }

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

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

    // Lors de la plantation d'un arbre
    public void install(){
        System.out.println("x:"+x+" y:"+y+" position, un arbre de couleur "+color+" a été installé!");
    }
}

public class TreeFactory {
    // La structure de données HashMap est utilisée pour gérer les arbres créés.
    public static final Map treeMap = new HashMap<>();
    
   
    public static Tree getTree(String treeColor){
        // Recherche dans la Map d'un arbre de la couleur saisie. Si un arbre est trouvé, il est fourni.
        Tree tree = (Tree)treeMap.get(treeColor); 

       // Si aucun arbre de la même couleur n'existe encore dans la Map, un nouvel objet est créé et fourni.
        if(tree == null){
            tree = new Tree(treeColor);
            treeMap.put(treeColor, tree);
            System.out.println("New object created");
        }

        return tree;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.println("Enter the desired color :)");
        for(int i=0;i<10;i++){
            // Saisie de la couleur de l'arbre
            String input = scanner.nextLine();
            // Obtention d'un arbre de l'usine
            Tree tree = (Tree)TreeFactory.getTree(input);
            // Réglage de x et y de l'arbre
            tree.setX((int) (Math.random()*100));
            tree.setY((int) (Math.random()*100));
            // Installation de l'arbre
            tree.install();
        }
    }


Différence avec le modèle Singleton

Le modèle Singleton permet de créer un seul arbre dans la classe Tree. Par conséquent, si vous utilisez le modèle Singleton, vous devez modifier la couleur du seul objet créé. En d'autres termes, le modèle Singleton permet de ne posséder qu'un seul objet, quel que soit son type.


Cas d'utilisation

Le pool de constantes String de Java utilise le modèle Flyweight.


Elles peuvent renvoyer des objets de type inférieur à celui du type de retour.

Si vous avez déjà utilisé la méthode asList() de la classe utilitaire Arrays, vous comprenez cet avantage.


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


La méthode renvoie une valeur encapsulée dans un ArrayList, qui est une implémentation inférieure de List. L'utilisateur n'a pas besoin de connaître cette implémentation. En d'autres termes, la flexibilité de pouvoir choisir la classe de l'objet renvoyé permet au développeur de ne pas exposer l'implémentation et de renvoyer l'implémentation, ce qui permet de maintenir une petite API.


Histoire des méthodes statiques d'interface Java

Avant Java 8, il était impossible de déclarer des méthodes statiques dans les interfaces. Par conséquent, si vous aviez besoin d'une méthode statique qui renvoyait une interface nommée "Type", vous deviez créer une classe compagnon nommée "Types" qui ne pouvait pas être instanciée et y définir la méthode.


Un exemple typique est les 45 implémentations utilitaires fournies par JCF, dont la plupart sont obtenues via des méthodes d'usine statiques dans une seule classe compagnon, java.util.Collections. En particulier, parmi ces implémentations, certaines sont privées et ne peuvent être instanciées que par des méthodes d'usine statiques (elles ne peuvent évidemment pas être héritées).


De plus, les 45 implémentations ne sont pas non plus exposées, ce qui permet de créer une API beaucoup plus petite.


// Exemple d'interface et de classe compagnon


Cependant, à partir de Java 8, il est possible d'ajouter directement des méthodes statiques aux interfaces, ce qui évite la nécessité de définir des classes compagnons.


Elles peuvent renvoyer des objets de différentes classes en fonction des paramètres d'entrée.

Au-delà du simple renvoi de types inférieurs, il est possible de renvoyer des types inférieurs différents en fonction de la valeur des paramètres. Par exemple, si vous souhaitez renvoyer un MemberStatus différent en fonction de la note, vous pouvez créer une méthode d'usine statique comme celle-ci et y inclure la logique de comparaison.


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("Aucun objet MemberStatus correspondant n'existe."));
    }

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

@DisplayName("MemberStatus test")
class MemberStatusTest {

    @ParameterizedTest
    @CsvSource(value = {"0:BASIC", "30:BASIC", "50:INTERMEDIATE", "70:INTERMEDIATE", "80:ADVANCED", "100:ADVANCED"}, delimiter = ':')
    @DisplayName("Renvoie un MemberStatus différent en fonction de la note.")
    void of(int input, MemberStatus expected) {
        assertThat(MemberStatus.of(input)).isEqualTo(expected);
    }


La classe de l'objet à renvoyer n'a pas besoin d'exister au moment de la rédaction de la méthode d'usine statique.

Dans cette phrase, classe de l'objetfait référence au fichier de classe que nous écrivons.

Notez que Class représente l'objet Class alloué dans la zone de mémoire du tas lorsque le chargeur de classe charge la classe. Cet objet Class contient diverses métadonnées sur la classe que nous avons écrite.


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"); // Réflexion
            temp = (StaticFactoryMethodType) childClass.newInstance(); // Réflexion

        } catch (ClassNotFoundException e) {
           System.out.println("La classe n'existe pas.");
        } catch (InstantiationException  e) {
            System.out.println("Impossible de charger en mémoire.");
        } catch (IllegalAccessException  e) {
            System.out.println("Erreur d'accès au fichier de classe.");
        }

        return temp;
    }


Dans le code ci-dessus, on peut voir que l'objet Class est créé à partir de l'emplacement de l'implémentation de l'interface, et que la technique de réflexion est utilisée pour initialiser l'implémentation réelle. À ce moment-là, au moment de la rédaction de la méthode d'usine statique, la classe StaticFactoryMethodTypeChild n'a pas besoin d'exister.


Si aucune implémentation n'existe dans le chemin algorithm.dataStructure.StaticFactoryMethodTypeChild au moment de l'utilisation de la méthode d'usine statique, une erreur se produira, mais au moment de la rédaction de la méthode d'usine statique, il n'y aura pas de problème, ce qui la rend flexible.


public interface Test {

    int sum(int a, int b);

    // Test est une interface et il n'y a pas d'implémentation, mais il n'y a pas de problème au moment de la rédaction de la méthode d'usine statique.
    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 se produit
    }


Vous pouvez obtenir la même flexibilité sans utiliser la réflexion. Dans la méthode d'usine statique create() de Test, il n'y a pas de problème au moment de la rédaction, même s'il n'y a pas d'implémentation. Bien sûr, un NPE se produira lors de l'utilisation réelle, vous devez donc renvoyer l'implémentation plus tard.


Cette flexibilité est à la base de la création de frameworks de fournisseurs de services, dont JDBC est un exemple typique. Dans le framework de fournisseurs de services JDBC, le fournisseur est l'implémentation du service, et le framework contrôle la fourniture de ces implémentations aux clients, en séparant les clients des implémentations (DIP).


  • Composants d'un framework de fournisseur de services
    • Interface de service
      • Définit le comportement de l'implémentation.
      • JDBC Connection
    • API d'enregistrement de fournisseur
      • Le fournisseur enregistre l'implémentation.
      • JDBC DriverManager.registerDriver()
    • API d'accès au service
      • Utilisée par le client pour obtenir une instance du service. Si aucune condition n'est spécifiée, l'implémentation par défaut ou les implémentations prises en charge sont renvoyées en alternance.
      • Correspondance avec la méthode d'usine statique
      • JDBC DriverManager.getConnection()
    • (Facultatif) Interface de fournisseur de service
      • Si elle n'existe pas, la réflexion doit être utilisée pour instancier chaque implémentation.
      • JDBC Driver


Le modèle de framework de fournisseur de service existe en plusieurs variantes, notamment le modèle Bridge, le framework d'injection de dépendances, etc.


Exemple JDBC typique

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


En général, JDBC est écrit comme indiqué ci-dessus. Class.forName() est utilisé pour enregistrer OracleDriver, qui est l'une des implémentations de Driver, et DriverManager.getConnection() est utilisé pour obtenir l'une des implémentations de Connection, qui est Connection pour OracleDriver.


Ici, Connection est l'interface de service, DriverManager.getConnection() est l'API d'accès au service, et Driver est l'interface de fournisseur de service. Cependant, l'API d'enregistrement de fournisseur, DriverManager.registerDriver(), n'a pas été utilisée. Pourtant, nous pouvons enregistrer OracleDriver, qui est l'implémentation de Driver, avec Class.forName() uniquement. Comment est-ce possible ?


Fonctionnement de Class.forName()

Cette méthode prend le nom du fichier de classe physique en tant qu'argument et demande à la JVM de charger cette classe. Le chargeur de classe stocke alors les métadonnées de la classe dans la zone de méthode et alloue l'objet Class dans la zone de tas. De plus, une fois le chargement de la classe terminé, les champs statiques et le bloc statique sont initialisés, et c'est à ce moment-là que l'API d'enregistrement de fournisseur est utilisée.


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); // Enregistrement d'OracleDriver
            }
        } catch (RuntimeException runtimeexception) {
        } catch (SQLException sqlexception) {
        }
    }

    ...


En effet, on peut voir qu'OracleDriver utilise DriverManager.registerDriver() dans le bloc statique pour enregistrer OracleDriver, qui est l'implémentation de Driver.


Analyse de la 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("Driver enregistré");
        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();
    }


La classe DriverManager est en réalité beaucoup plus complexe, mais elle est similaire à ce qui précède si on ne s'intéresse qu'aux aspects essentiels. Comme indiqué ci-dessus, registerDriver() est appelé dans le bloc statique d'OracleDriver pour enregistrer OracleDriver, et l'utilisateur peut obtenir l'implémentation de Connection en appelant getConnection().


En regardant de plus près la méthode getConnetion() de l'API d'accès des utilisateurs, on peut voir qu'elle obtient une Connection à partir de l'interface Driver. Si l'interface Driver de l'interface de fournisseur de services n'existait pas, la réflexion, comme Class.forName(), pourrait être utilisée pour renvoyer l'implémentation de Connection souhaitée. À ce moment-là, l'implémentation de Connection n'a pas besoin d'exister au moment de la rédaction de la méthode d'usine statique.


Au lieu de cela, nous utilisons l'interface Driver et pouvons facilement obtenir l'implémentation de Connection correspondante après avoir enregistré dynamiquement l'implémentation de Driver.


Notez que j'ai analysé le code JDK réel de la méthode getConnection() de DriverManager, mais vous pouvez l'ignorer si vous n'y êtes pas intéressé.


@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()));


Tout d'abord, la méthode statique publique getConnection() est appelée, et url, Properties et CallerClass sont transmis à la méthode statique privée getConnection() en tant qu'arguments. À ce moment-là, Reflection.getCallerClass() sert à obtenir la classe qui a appelé la méthode statique publique getConnection(). Si la classe Car appelle getConnection(), Reflection.getCallerClass() permettra d'obtenir l'objet Class.


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("The url cannot be null", "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("No suitable driver found for "+ url, "08001");


callerCL est un objet chargeur de classe qui est créé par le chargeur de classe de l'appelant ou du thread actuel. Ensuite, un aDriver est extrait de registeredDrivers, qui est la liste des pilotes enregistrés dans l'application actuelle. Si ce Driver est true selon isDriverAllowed(), l'objet Connection est obtenu à partir de ce Driver et renvoyé. isDriverAllowed() vérifie si aDriver existe dans l'appelant.


Avantages du framework JDBC

Le point principal du framework JDBC est que Driver et Connection, qui sont des interfaces, et leurs classes d'implémentation réelles qui implémentent ces interfaces sont fournies séparément. L'utilisation d'interfaces permet de créer un cadre, et chaque classe d'implémentation peut être créée en fonction de ce cadre, ce qui offre une grande flexibilité.


Par conséquent, même si de nouveaux SGBD sont créés, les fournisseurs de ces SGBD peuvent fournir des implémentations de Driver et Connection, ce qui permet aux développeurs Java d'utiliser la même API que les autres pilotes de SGBD.


Inconvénients des méthodes d'usine statiques

Lorsque vous héritez, vous avez besoin d'un constructeur public ou protégé. Par conséquent, si vous ne fournissez que des méthodes d'usine statiques, vous ne pouvez pas créer de sous-classes.


Cependant, cette restriction est plutôt un avantage car elle favorise la composition plutôt que l'héritage et parce qu'elle doit être respectée pour créer des types immuables.


Les méthodes d'usine statiques sont difficiles à trouver pour les programmeurs.

Comme elles n'apparaissent pas clairement dans la description de l'API comme les constructeurs, les développeurs doivent atténuer le problème en écrivant une bonne documentation d'API et en choisissant des noms de méthodes qui suivent des conventions largement connues.


Conventions de dénomination des méthodes d'usine statiques

  • from
    • Accepte un paramètre et renvoie une instance de ce type.
    • Date date = Date.from(instant);
  • of
    • Accepte plusieurs paramètres et renvoie une instance du type approprié.
    • Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOf
    • Version plus détaillée de from et of.
    • BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • instance ou getInstance
    • Renvoie l'instance spécifiée par le paramètre, mais ne garantit pas que c'est la même instance.
    • StackWalker luke = StackWalker.getInstance(options);
  • create ou newInstance
    • Semblable à instance ou getInstance, mais garantit qu'une nouvelle instance est créée et renvoyée à chaque fois.
    • Object newArray = Array.newInstance(classObject, arraylen);
  • getType
    • Semblable à getInstance, mais utilisé lorsque la méthode d'usine est définie dans une classe différente de celle à créer.
    • FileStore fs = Files.getFileStore(path);
  • newType
    • Semblable à newInstance, mais utilisé lorsque la méthode d'usine est définie dans une classe différente de celle à créer.
    • BufferedReader br = Files.newBufferedReader(path);
  • type
    • Version concise de getType et newType.
    • List<Complaint> litany = Collections.list(legacyLitany);


Résumé

Les méthodes d'usine statiques et les constructeurs publics ont chacun leur propre utilité, utilisez-les judicieusement.


Sources

제이온
제이온
제이온
제이온
[Effective Java] Item 5. Utilisez l'injection de dépendances au lieu de spécifier les ressources Si une classe dépend de ressources externes, il est préférable d'éviter d'utiliser les singletons et les classes utilitaires statiques. L'injection de dépendances peut améliorer la flexibilité, la réutilisabilité et la testabilité de la classe, et l'utili

28 avril 2024

[Effective Java] Item 2. Si vous avez beaucoup de paramètres dans le constructeur, envisagez d'utiliser un générateur Lors de la création d'objets avec un grand nombre de paramètres, l'utilisation du modèle de générateur permet de rendre le code plus propre et plus lisible. Créez un objet générateur avec des paramètres obligatoires, définissez des paramètres optionnels à

27 avril 2024

[Effective Java] Item 3. Garantir un singleton avec un constructeur privé ou un type énuméré Cet article présente trois méthodes pour implémenter le modèle de conception singleton en Java (membre public statique, méthode d'usine statique, type énuméré) et explique les avantages et les inconvénients de chaque méthode, ainsi que les précautions à p

27 avril 2024

[Javascript] Structure d'objet (V8) L'objet JavaScript dans le moteur V8 est optimisé comme une structure en fonction de l'état, passant du mode Fast, optimisé comme une structure, au mode Dictionary qui fonctionne comme une table de hachage. Le mode Fast est rapide lorsque les clés et les
곽경직
곽경직
곽경직
곽경직
곽경직

18 mars 2024

[Non-majors, Surviving as Developers] 14. Résumé des questions d'entrevue technique fréquemment posées aux développeurs débutants Guide de préparation aux entrevues techniques pour les développeurs débutants. Zone de mémoire principale, structures de données, RDBMS et NoSQL, programmation procédurale et orientée objet, surcharge et surcharge, algorithmes de remplacement de page, pro
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 avril 2024

[Développeur non spécialisé, survivre en tant que développeur] 16. Conseils pour créer un portfolio de développeur junior Un développeur junior (en particulier un non-spécialiste) doit clairement expliquer les services ou les fonctionnalités qu'il a développés lors de la création d'un portfolio, en plus de ses compétences techniques. Par exemple, si le projet est une « commu
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 avril 2024

Créer une CLI élégante avec Rust Cet article explique comment implémenter une application CLI en Rust. Nous utiliserons les bibliothèques clap et ratatui pour créer un programme CLI avec des fonctionnalités de connexion et de déconnexion. Nous présentons les aspects clés du développement
곽경직
곽경직
곽경직
곽경직
곽경직

13 mars 2024

[React Hook] useState Ce document explique en détail pourquoi l'hook useState de React provoque le rendu complet du composant lors de la mise à jour, comment conserver la valeur et comment il fonctionne en interne. L'analyse du code ReactFiberHooks.js permet de comprendre comm
Sunrabbit
Sunrabbit
Sunrabbit
Sunrabbit

14 mars 2024

Qu'est-ce que JWT (JSON Web Token) ? JSON Web Token (JWT) est un standard ouvert pour la transmission sécurisée d'informations. Il utilise des jetons signés pour garantir l'intégrité et la sécurité des informations. L'en-tête contient le type de jeton et l'algorithme de signature, tandis que
Seize the day
Seize the day
Seize the day
Seize the day
Seize the day

4 mars 2024