Skip to content

8. [TD]: طبقة [الأعمال]

الكلمات الرئيسية: بنية متعددة الطبقات، Spring، حقن التبعية.

8.1. الدعم

 

يحتوي المجلد [support / chap-08] على مشروع Eclipse الخاص بهذا الفصل.

8.2. تكوين Maven

  

سيستند مشروع [elections-metier-dao-jdbc] إلى مشروع [elections-dao-jdbc-01]. سنقوم بتثبيت ملف JAR من المشروع الأخير في مستودع Maven المحلي:

 

وبمجرد الانتهاء من ذلك، يصبح تكوين Maven لمشروع Eclipse [elections-metier-dao-jdbc] كما يلي:

  

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>istia.st.elections</groupId>
    <artifactId>elections-metier-dao-jdbc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.7.RELEASE</version>
    </parent>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <!-- DAO -->
        <dependency>
            <groupId>istia.st.elections</groupId>
            <artifactId>elections-dao-jdbc-01</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
 
    <!-- plugins -->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>config.AppConfig</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
            <!-- to install the project artifact in the local Maven repository -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>
        </plugins>
    </build>
</project>
  • الأسطر 21–25: التبعية لملف JAR الخاص بمشروع [elections-jdbc-01]. انسخ هذه الأسطر مباشرةً إلى ملف [pom.xml] الخاص بالمشروع الذي تريد استيراده:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>istia.st.elections</groupId>
    <artifactId>elections-dao-jdbc-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
...
  • الأسطر 26–37: التبعيات المطلوبة للاختبار. على الرغم من وجودها في ملف [pom.xml] لمشروع [elections-jdbc-01]، يجب تضمينها هنا لأن سمة [<scope>test</scope>] الخاصة بها تعني أنها لم تُدرج في ملف JAR الموجود في مستودع Maven المحلي؛

8.3. تكوين Spring

  

package elections.metier.config;
 
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

@Import({ elections.dao.config.AppConfig.class })
@EnableCaching
@ComponentScan(basePackages = { "elections.metier.service" })
public class MetierConfig {
}
  • السطر 7: نقوم باستيراد جميع الفاصوليا المحددة في طبقة [DAO
  • السطر 8: نقوم بتمكين ذاكرة التخزين المؤقت. لا نعيد تعريف حبة [CacheManager]، لأنها محددة بالفعل في طبقة [DAO
  • السطر 9: تحدد طبقة [business] حبات جديدة في حزمة [elections.business.service

8.4. واجهة [ IElectionsMetier]

  

ستحتوي طبقة [الأعمال] على الواجهة المعروضة في القسم 4.2. وإليك تذكير بها:


public interface IElectionsMetier {
 
    public ListeElectorale[] getListesElectorales();
 
    public int getNbSiegesAPourvoir();
 
    public double getSeuilElectoral();
 
    public void recordResultats(ListeElectorale[] listesElectorales);
 
    public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales);
 
}

8.5. فئة التنفيذ [ ElectionsMetier]

  

تنفذ هذه الفئة واجهة [IElectionsMetier]. سيكون للتنفيذ المقترح الهيكل التالي:


package elections.metier.service;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
 
import elections.dao.entities.ListeElectorale;
import elections.dao.service.IElectionsDao;
 
@Component
public class ElectionsMetier implements IElectionsMetier {
 
    // the access point to the [dao] layer instantiated by [Spring]
    @SuppressWarnings("unused")
    @Autowired
    private IElectionsDao electionsDao;

    // calculation of seats obtained
  @Override
    public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales) {
        throw new RuntimeException("[calculerSieges] not yet implemented");
    }
 
    // competing lists
  @Override
    public ListeElectorale[] getListesElectorales() {
        throw new RuntimeException("[getListesElectorales] not yet implemented");
    }
 
    // saving results
  @Override
    public void recordResultats(ListeElectorale[] listesElectorales) {
        throw new RuntimeException("[recordResultats] not yet implemented");
    }
 
    // number of seats to be filled
    @Override
    public int getNbSiegesAPourvoir() {
        throw new RuntimeException("[getNbSiegesAPourvoir] not yet implemented");
    }
 
    // electoral threshold
    @Override
    public double getSeuilElectoral() {
        throw new RuntimeException("[getSeuilElectoral] not yet implemented");
    }
 
}
  • السطر 10: فئة [ElectionsMetier] هي مكون Spring؛
  • السطر 11: فئة [ElectionsMetier] تنفذ واجهة [IElectionsMetier
  • السطران 15-16: حقن Spring لمرجع إلى طبقة [DAO
  • السطران 37 و44: يتم تخزين عدد المقاعد المطلوب شغلها والعتبة الانتخابية مؤقتًا؛

المهمة: اكتب فئة [ElectionsMetier]. استخدم التعليقات حيثما كانت متوفرة. لن نحاول التقاط (try/catch) استثناءات [ElectionsException] التي تنتقل من طبقة [DAO]. سنسمح لها بالانتقال إلى طبقة [UI]. نظرًا لأن فئة [ElectionsException] هي نوع استثناء غير محدد، فلا يوجد ما يقتضي معالجتها باستخدام كتلة try/catch.


8.6. فئة الاختبار

  

ستكون فئة الاختبار JUnit بالشكل التالي:


package tests;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
import dao.config.AppConfig;
import dao.entities.ElectionsException;
import metier.service.IElectionsMetier;
 
@SpringApplicationConfiguration(classes = MetierConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Test01 {
 
    // business] layer
    @Autowired
    static private IElectionsMetier electionsMetier;
 
    /**
     * vérification 1 : méthode de calcul des sièges on fixe en dur les listes
     */
    @Test
    public void calculSieges1() {
        // create a table of the 7 candidate lists (name, vote)
 
        // the seats for each list are calculated
 
        // we check the results (seats, votes, eliminates)
 
        // temporary
        throw new RuntimeException("[calculSieges1] not yet implemented");
    }
 
    /**
     * vérification 2 : méthode de calcul des sièges on demande les listes à la
     * couche [metier] puis on fixe en dur les voix
     */
    @Test
    public void calculSieges2() {
        // the table of 7 candidate lists is retrieved as a base
 
        // the voices are hard-fixed
 
        // the seats obtained by each list are calculated
 
        // we check the results (seats, votes, eliminates)
 
        // temporary
        throw new RuntimeException("[calculSieges2] not yet implemented");
    }
 
    /**
     * vérification 3 méthode de calcul des sièges on provoque une exception
     */
    @Test(expected = ElectionsException.class)
    // write a test that causes an exception of type [ElectionsException]
    public void calculSieges3() {
        // create a table of 25 candidate lists, each with 1 vote
        // all 25 lists will have the same number of votes (4%)
 
        // calculation of seats - normally there should be a ElectionsException
        // with an electoral threshold of 5%
 
        // temporary
        throw new RuntimeException("[calculSieges3] not yet implemented");
    }
 
    /**
     * enregistrement des résultats de l'élection
     */
    @Test
    public void ecritureResultatsElections() {
        // create the table of 7 candidate lists
 
        // the voices are hard-fixed
 
        // the seats obtained by each list are calculated
 
        // results are entered into the database
 
        // reread lists in base
 
        // we check the results (seats, votes, eliminates)
 
        // temporary
        throw new RuntimeException("[ecritureResultatsElections] not yet implemented");
    }
}

المهمة: اكتب طرق الاختبار الأربع باستخدام التعليقات كدليل. تذكر أنه عند تشغيل هذه الطرق، يكون الحقل [electionsMetier] في السطر 19 قد تم تهيئته بالفعل. تحقق من نجاح اختبار JUnit.


8.7. إنشاء أرشيف طبقة [business]

كما فعلنا مع طبقة [DAO]، نضع أرشيف مشروع [elections-metier-dao-jdbc] في مستودع Maven المحلي:

 

ملاحظة: قد تفشل هذه العملية إذا كان مشروع Eclipse الخاص بك مرتبطًا بـ JRE (بيئة تشغيل Java) بدلاً من JDK (مجموعة أدوات تطوير Java). للتحقق من ذلك، اتبع الإرشادات الواردة في القسم 3.1. إذا وجدت أن لديك JRE وليس JDK، فقم بربط مشروعك بـ JDK كما هو موضح في ذلك القسم.

8.8. الخلاصة

دعونا نستعرض البنية العامة لتطبيق [Elections] الذي نقوم ببنائه:

لقد أنشأنا طبقتي [business] و [DAO]. سنقوم الآن بإنشاء طبقة [UI]. سنقترح طريقتين لتنفيذ هذه الطبقة:

  • تطبيق "وحدة التحكم"
  • تطبيق واجهة مستخدم رسومية