Skip to content

9. [TD]: [ui] katmanının bir konsol programı ile uygulaması

Anahtar kelimeler: çok katmanlı mimari, Spring, bağımlılık enjeksiyonu.

9.1. Support

[1]'te, [support / chap-09] klasörü, konsol uygulamasının [UI] katmanına ait Eclipse projesini içerir.

9.2. Maven Yapılandırması

[elections-ui-metier-dao-jdbc] Eclipse projesi, aşağıdaki [pom.xml] Maven dosyası ile yapılandırılmıştır:


<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-ui-metier-dao-jdbc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>elections-ui-metier-dao-jdbc</name>

    <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>
        <!-- iş süreci -->
        <dependency>
            <groupId>istia.st.elections</groupId>
            <artifactId>elections-metier-dao-jdbc</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 Testi -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- eklentiler -->
    <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>
            <!-- proje artefaktının yerel Maven deposuna kurulması için -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>
        </plugins>
    </build>
</project>
  • 22-26. satırlar: [métier] katmanının arşivi ve buna bağlı olarak [DAO] katmanının arşivi içe aktarılır;

9.3. Spring Yapılandırması

  

[UiConfig] sınıfı, Spring uygulamasını yapılandırır:


package elections.ui.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

import elections.metier.config.MetierConfig;

@Import(MetierConfig.class)
@ComponentScan(basePackages = { "elections.ui.service" })
public class UiConfig {
}
  • 8. satır: [métier] katmanında tanımlanan bean'ler içe aktarılır. Bu katman, [DAO] katmanında tanımlanan bean'leri zaten içe aktarmıştı. Dolayısıyla burada üç katmanın bean'lerine erişim sağlanır;
  • 9. satır: [elections.ui.service] paketi başka bean'ler içerir;

9.4. [UI] katmanının arayüzü

  

[UI] katmanının Java arayüzünün ne olabileceğini anlamak için, bu arayüzü kimin kullanacağını bilmemiz gerekir. Bu, yukarıdaki şemadaki kullanıcı değil, uygulamayı bir bütün olarak başlatacak programdır.

[IElectionsUI] arayüzü, uygulamayı başlatacak olan ana program [main]'e sunulur. [main], [ui] katmanından ne isteyebilir? Seçimde eksik olan verileri girecek olan kullanıcıyla iletişime geçmesini isteyebilir. Aşağıdaki minimum arayüzü kullanacağız:


package istia.st.elections.ui;

public interface IElectionsUI {
    /**
     * lance le dialogue avec l'utilisateur
     */
    public void run();
}
  • 7. satır: Arayüzün tek bir yöntemi vardır: run. Bu yöntemi çağırarak, [ui] katmanından kullanıcıyla etkileşime başlaması istenir.

9.5. Uygulamanın başlatma sınıfı

  

Uygulamanın başlatma sınıfı, [main] adlı statik bir yönteme sahip bir Java sınıfıdır. Bu yöntem, [ui, metier, demo] katmanlarının örneklerini oluşturmalı ve [ui] katmanından kullanıcıyla etkileşime geçmesini istemelidir. Bu sınıf, aşağıdaki [AbstractBootElections] sınıfı olabilir:


package elections.ui.boot;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import elections.dao.entities.ElectionsException;
import elections.ui.config.UiConfig;
import elections.ui.service.IElectionsUI;

public abstract class AbstractBootElections {

    // Spring bağlamının alınması
    protected AnnotationConfigApplicationContext ctx;

    public void run() {
        // [ui] katmanının örneklenmesi
        IElectionsUI electionsUI = null;
        try {
            // Spring bağlamının alınması
            ctx = new AnnotationConfigApplicationContext(UiConfig.class);
            // [ui] katmanının alınması
            electionsUI = getUI();
        } catch (RuntimeException ex) {
            // hata bildiriliyor
            afficheExceptions("Les erreurs suivantes se sont produites :", ex);
            // uygulama durduruluyor
            System.exit(1);
        }
        // [ui] katmanının yürütülmesi
        try {
            electionsUI.run();
        } catch (ElectionsException ex2) {
            // hata bildiriliyor
            afficheExceptions("Les erreurs suivantes se sont produites :", ex2);
            // uygulama durduruluyor
            System.exit(3);
        } catch (RuntimeException ex1) {
            // hata bildiriliyor
            afficheExceptions("Les erreurs suivantes se sont produites :", ex1);
            // uygulama durduruluyor
            System.exit(2);
        }
    }

    protected abstract IElectionsUI getUI();

    private void afficheExceptions(String message, ElectionsException ex) {
        // mesaj görüntüleniyor
        System.out.println(String.format("%s -------------", message));
        System.out.println(String.format("Code erreur : %d", ex.getCode()));
        // hatalar görüntülenir
        for (String erreur : ex.getErreurs()) {
            System.out.println(String.format("-- %s", erreur));
        }

    }

    public void afficheExceptions(String message, Exception ex) {
        // mesaj görüntülenir
        System.out.println(String.format("%s -------------", message));
        // istisna yığını görüntülenir
        Throwable cause = ex;
        while (cause != null) {
            System.out.println(String.format("-- %s", cause.getMessage()));
            cause = cause.getCause();
        }
    }
}
  • 19. satır: Spring bağlamı örneklenir: çeşitli yapılandırma dosyalarında tanımlanan tüm bean'ler oluşturulacaktır;
  • 21. satır: [IElectionsUI] arayüzünü uygulayan bean'e bir referans alınır. [IElectionsUI] arayüzünü iki bean ile uygulayacağız:
    • konsol uygulaması için [ElectionsConsole];
    • Swing uygulaması için [ElectionsSwing];

[getUI] yöntemi soyuttur (44. satır). Nitekim, [AbstractBootElections] sınıfı iki sınıfın üst sınıfı olacaktır:

  • [BootElectionsConsole], üst sınıfına [ElectionsConsole] bean'ini sağlayacak;
  • [BootElectionsSwing], üst sınıfına [ElectionsSwing] bean'ini sağlayacaktır;
  • 30. satır: arayüzün [run] yöntemi yürütülür;

İstisnalar çeşitli yerlerde yönetilir:

  • 22-27. satırlar: Spring bağlamının örneklendirilmesi sırasında bir istisna meydana gelebilir;
  • satır 31-41: [UI] katmanının yürütülmesi sırasında bir istisna meydana gelebilir. İki tür istisna ayırt edilir:
    • [DAO] katmanının tetiklediği [ElectionsException] sınıfı;
    • çalıştırma sırasında ortaya çıkabilecek diğer istisnalar için [RuntimeException] sınıfı;

[BootElectionsConsole] sınıfı, konsol uygulamasını başlatan sınıftır. Kod şöyledir:


package elections.ui.boot;

import elections.ui.service.IElectionsUI;

public class BootElectionsConsole extends AbstractBootElections{
    public static void main(String[] arguments) {
        new BootElectionsConsole().run();
    }

    @Override
    protected IElectionsUI getUI() {
        return ctx.getBean("electionsConsole",IElectionsUI.class);
    }
}
  • 5. satırda, [BootElectionsConsole] sınıfı, [AbstractBootElections] sınıfını genişletir. Bu nedenle, üst sınıfı tarafından soyut olarak bildirilen [getUI] yöntemini uygulamalıdır;
  • 10-13. satırlar: [getUI] yönteminin uygulanması;
  • 12. satır: [electionsConsole] adlı bean'in [IElectionsUI] arayüzünü uyguladığı belirtilir. [ctx], üst sınıfta şu bildirimle tanımlanan Spring bağlamıdır:

    // Spring bağlamını al
    protected AnnotationConfigApplicationContext ctx;

Alan, [protected] özniteliğine sahip olduğu için alt sınıflarda görülebilir.

  1. satırdaki bean şu şekilde tanımlanacaktır:

@Component
public class ElectionsConsole implements IElectionsUI {

Bu bean'in varsayılan adı, sınıf adının ilk harfi küçük harfle yazılmış halidir. Aşağıdaki gibi açıkça yazarak bu varsayılan addan kurtulabilirsiniz:

@Component(nom_du_bean_entre_guillemets)

Swing uygulamasını çalıştıracak [BootElectionsSwing] sınıfı şu şekilde olabilir:


package elections.ui.boot;

import elections.ui.service.IElectionsUI;

public class BootElectionsSwing extends AbstractBootElections {
    public static void main(String[] arguments) {
        new BootElectionsSwing().run();
    }

    @Override
    protected IElectionsUI getUI() {
        return ctx.getBean("electionsSwing", IElectionsUI.class);
    }
}

Sınıfların ortak davranışlarını bir üst sınıfta birleştirip, alt sınıfların kendilerine özgü ayrıntıları uygulamalarına izin verilen bu tasarım modeline Strategy tasarım modeli denir. Bu tasarım modeli, tüm alt sınıflara ortak bir davranış dayatır.

9.6. [ElectionsConsole] uygulama sınıfı

  

[ui] katmanının ilk uygulama sınıfımız, kullanıcıyla iletişim kurmak için konsolu kullanan bir sınıf olacaktır. İşte Eclipse konsolunda elde edilen bir diyalog örneği:


Il y a 7 listes en compétition. Veuillez indiquer le nombre de voix de chacune d'elles :
Nombre de voix de la liste [A] : 2500
Nombre de voix de la liste [B] : 4500
Nombre de voix de la liste [C] : x
Nombre de voix incorrect. Veuillez recommencer
Nombre de voix de la liste [C] : 8000
Nombre de voix de la liste [D] : 12000
Nombre de voix de la liste [E] : 16000
Nombre de voix de la liste [F] : 25000
Nombre de voix de la liste [G] : 32000

Résultats de l'élection

[G,32000,2,false]
[F,25000,2,false]
[E,16000,1,false]
[D,12000,1,false]
[C,8000,0,false]
[B,4500,0,true]
[A,2500,0,true]

[ElectionsConsole] sınıfının iskeleti şu şekilde olabilir:


package elections.ui.service;

import java.util.Comparator;
import java.util.Scanner;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import elections.dao.entities.ListeElectorale;
import elections.metier.service.IElectionsMetier;

@Component
public class ElectionsConsole implements IElectionsUI {

    @Autowired
    private IElectionsMetier electionsMetier;

    @Override
    public void run() {
        // verilerin girilmesi
        try (Scanner clavier = new Scanner(System.in)) {
            // [metier] katmanından rekabet halindeki listeler isteniyor

            // oyların girilmesi

        }
        // koltuk hesaplaması yapılıyor

        // sonuçlar kaydediliyor

        // listeler oy sayısına göre azalan sırada sıralanıyor

        // listeler görüntüleniyor
    }

    // seçim listelerinin karşılaştırma sınıfı
    class CompareListesElectorales implements Comparator<ListeElectorale> {

        // oy sayısına göre iki aday listesinin karşılaştırılması
        @Override
        public int compare(ListeElectorale listeElectorale1, ListeElectorale listeElectorale2) {
            // bu iki listenin oyları karşılaştırılır
            int nbVoix1 = listeElectorale1.getVoix();
            int nbVoix2 = listeElectorale2.getVoix();
            if (nbVoix1 < nbVoix2) {
                return +1;
            } else {
                if (nbVoix1 > nbVoix2)
                    return -1;
                else
                    return 0;
            }
        }
    }

}
  • 12. satır: [ElectionsConsole] sınıfı bir Spring bileşenidir;
  • 13. satır: sınıf, [IElectionsUI] arayüzünü uygular
  • 15-16. satırlar: Spring tarafından [metier] katmanına bir referans enjeksiyonu;
  • satır 18-34: [IelectionsUI] arayüzünün [run] yöntemi;

21-28. satırlardaki try, try-with-resources olarak adlandırılır ve sözdizimi şöyledir:

1
2
3
try(ressource){
}
  1. satırdaki kaynak, [java.lang.AutoCloseable] arayüzünü uygulamalıdır. Kaynak, 1. satırda açılır ve 3. satırdan sonra, bu iki satır arasında yürütülen kodda istisna olsun ya da olmasın, otomatik olarak kapatılır. Bu sözdizimi, ne olursa olsun açık bir kaynağın mutlaka kapatılmasını sağlar.

Yapılması gereken iş: [run] yönteminin kodunu yazın. Yorumlardan yararlanabilirsiniz.