web-dev-qa-db-fra.com

Initialisation des objets dans le constructeur

J'ai ci-dessous constructeur, où cela crée un classeur dans le constructeur. Je lis cela, idéalement, nous ne devrions pas créer d'objets dans le constructeur, nous devrions simplement avoir des attributions qui sont passées.

public ExcelWriter() {
        workbook = new HSSFWorkbook();
        //other code
    }

Est-ce que ça va de créer des objets fixes comme ci-dessus? Quelle est la solution alternative idéale? et de la perspective des tests unitaires? Si vous devez passer du classeur du code de la méthode d'appel dans une autre classe, nous devons créer l'objet du classeur même là aussi.

Est plus tard est une meilleure approche? Comment c'est mieux ou des questions par rapport à l'approche du constructeur?

6
dgr

Pour les programmeurs débutants, c'est bien.

Cependant, comme vous l'avez dit, si vous souhaitez tester cette classe ExcelWriter classe, vous pouvez peut-être donner l'objet HSSFWorkbook comme argument dans le constructeur plutôt que de la créer vous-même. De cette façon, vous pouvez utiliser le vrai dans votre code et utiliser un moqueur dans les tests de l'unité. Cette pratique est appelée injection de dépendance .

Donc, votre constructeur ressemblerait à:

public ExcelWriter(HSSFWorkbook hssfWorkBook) {
    workbook = hssfWorkBook;
    // other code
}

Ensuite, ailleurs dans votre code, vous appelez ce constructeur:

HSSFWorkbook myWorkbook = new HSSFWorkbook();
ExcelWriter myExcelWriter = new ExcelWriter(myWorkbook);

Et votre test de l'unité serait quelque chose comme:

HSSFWorkbook myMockedWorkbook = // create a mock
ExcelWriter testWriter = new ExcelWriter(myMockedWorkbook);

Si vous voulez faire cela encore mieux, utilisez des interfaces, vous allez donc vous retrouver avec deux classes distinctes:

public interface IWorkbook {}

public class RealWorkbook implements IWorkbook {
    // this is the one for in your code
}

public class FakeWorkbook implements IWorkbook {
    // this is the one you use in your unit test
}
11
Jelle

Rien dans le monde réel n'est idéal. Mais une solution alternative est appelée injection de dépendance :

public class ExcelWriter {
    Workbook workbook;
    public ExcelWriter(Workbook workbook) {
        this.workbook = workbook;
    }
    //other code
}

public void main(){        
    Writer writer = new ExcelWriter( new HSSFWorkbook() );       

    //other code
}

De cette façon ExcelWriter peut fonctionner avec n'importe quel type de Workbook.

5
candied_orange

Il tombe en sémantique.

Si l'instanciation est dans le contexte d'un emballage pour améliorer la fonctionnalité sur un classeur (héritage ou composition), instantiriez l'instanciation de l'objet dans le constructeur. Vous appliqueriez la règle "Composition sur l'héritage".

Si vous composez des objets pour créer un nouveau sémantique disjonctionnel, vous devez vous demander si vous souhaitez dépendre de la classe de béton car vous devez le savoir pour l'instancier.

Si vous n'avez aucun problème avec la dépendance concrète (qui peut violer le principe d'inversion de dépendance) L'instanciation d'objet dans le constructeur ou l'initialisation paresseuse est sémantiquement identique. L'initialisation paresseuse ne fait que ressortir l'instanciation jusqu'à ce qu'elle soit nécessaire. Vous résumez du point de temps lorsqu'un objet est créé.

Si vous pouvez avoir plusieurs versions d'un classeur sous une abstraction, vous devriez préférer passer l'objet dans le constructeur sous cette abstraction. Sur un objet de haut niveau, vous devez envisager la fonctionnalité des conteneurs. Il existe plusieurs possibilités de technologies d'injection de dépendance.

1
oopexpert