Wzorzec projektowy Bridge

Bridge = most.

Zadanie programistyczne

Smok programista ma za zadanie opracować system zapisu różnych informacji
w różny sposób. Wiadomość może być:

  • zaszyfrowana
  • tekstowa

Wiadomość może być zapisana:

  • na konsoli
  • w pliku

Rozwiązanie

  1. Stworzyć interface Logger, które określa miejsce zapisywania
  2. Stworzyć 2 klasy implementujące – jak można zauważyć jest to prosta implementacja.
  3. Stworzyć interface Message, które określa typ wiadomości
  4. Stworzyć 2 klasy implementujące – jak można zauważyć to każda klasa implementuje Message i zawiera obiekt typu Logger
  5. Stworzyć klasę Client i sprawdzić działanie.

Utworzenie nowej klasy np. DBLogger jest dziecinnie łatwe.
Utworzenie nowej klasy HTMLMessage tez jest wyjątkowo łatwe.

Klasy

Pakiet db

Klasa DBLogger
package bridge.db;
import bridge.localization.Logger;
public class DBLogger implements Logger {
    @Override
    public synchronized void log(String msg) {
        writeToDB("log_base", msg);
    }
    private static void writeToDB(String nazwaPBazy, String msg) {
        // Do napisania
    }
}
Klasa DerbyUtil
package bridge.db;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
class DerbyUtil {
    public static final String embdriver = "EmbeddedDriver";
    /**
     * Startuje DerbyEngine. Jeśi załadowano Embedded Driver można od razu
     * połączyć się z bazą danych. Jeśli załadowano ClientDriver aby połączyć
     * się z bazą danych należy wcześniej uruchomić NetworkServer na tym lub
     * zdalnym komputerze (w zależności gdzie znajduje się baza danych). Jeśli
     * baza danych znajduje się na innym komputerze to połączenie z nią jest
     * możliwe o ile na komputerze z bazą zostaną ustawione odpowiednie prawa
     * dostępu. Jeżeli nie zostaną ustawione możliwe jest połączenie tylko z
     * tego komputera, na którym baza się znajduje
     *
     * @param driverName - nazwa sterownika
     * @return - true -jeśli sterownik został załadowany i silnik bazy danych
     * Derby został uruchomiony, false - jeśli sterownik bazy danych nie został
     * załadowany i silnik bazy danych nie został uruchomiony
     */
    public static boolean startDerbyEngine(String driverName) {
        boolean started;
        loadDBDriver(driverName);
        started = true;
        return started;
    }
    /**
     * Ładuje wskazany sterownik bazy danych
     *
     * @param driverName - nazwa sterownika do załadowania
     * @return - true - jeśli sterownik został załadowany, false - w przeciwnym
     * przypadku
     * @throws IllegalArgumentException - wyrzucany wyjątek
     */
    private static boolean loadDBDriver(String driverName)
            throws IllegalArgumentException {
        if (driverName.equals("EmbeddedDriver")
                || driverName.equals("ClientDriver")) {
            try {
                try {
                    Class.forName("org.apache.derby.jdbc." + driverName)
                            .getDeclaredConstructor().newInstance((Object[]) null);
                } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                return false;
            }
        } else {
            throw new IllegalArgumentException("Niewłaściwa nazwa sterownika");
        }
        return true;
    }
    /**
     * Tworzy połaczenie z wbudowaną bazą danych. Ustawia właściwości określone
     * w łańcuchu znaków 'properties'     *
     *
     * @param dbName     - nazwa bazy danych lub ścieżka do bazy danych z nazwą bazy
     *                   danych na końcu
     * @param properties - pary właściwości połączenia (nazwa=właściwość)
     *                   oddzielone średnikami. Średnik na początku i końcu nie są potrzebne.
     * @return - połączenie z bazą danych
     */
    public static Connection connectEmbeddedDB(String dbName,
                                               String properties) {
        Connection conn = null;
        try {
            conn = DriverManager
                    .getConnection("jdbc:derby:" + dbName + ";" + properties);
        } catch (Throwable e1) {
            e1.printStackTrace();
        }
        return conn;
    }
    /**
     * Zamyka polecenie
     *
     * @param stat - polecenie do zamknięcia
     * @return - true - jeśli stat zostało zamknięta, false - w przeciwnym
     * wypadku
     */
    public static boolean close(Statement stat) {
        if (stat != null) {
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
    /**
     * Zamyka połączenie     *
     *
     * @param conn - połączenie do zamknięcia
     * @return - true - jeśli baza została zamknięta, false - w przeciwnym
     * wypadku
     */
    public static boolean close(Connection conn) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
    /**
     * Zamyka zbiór wynikowy     *
     *
     * @param rs - zamykany zbiór wynikowy
     * @return - true - jeśli został zamknięty, false w przeciwnym przypadku
     */
    public static boolean close(ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
    /**
     * Zamyka bazę o podanej nazwie     *
     *
     * @param dbName - nazwa bazy do zamknięcia
     * @return true - jesli baza zostala zamknieta, false - w przeciwnym wypadku
     */
    public static boolean shutdownEmbeddedDB(String dbName) {
        boolean shutted;
        boolean gotSQLExc = false;
        try {
            DriverManager
                    .getConnection("jdbc:derby:" + dbName + ";shutdown=true");
        } catch (SQLException se) {
            if (se.getSQLState().equals("XJ015")) {
                gotSQLExc = true;
            }
        }
        shutted = gotSQLExc;
        return shutted;
    }
    /**
     * Zatrzymuje silnik bazy danych Derby i wszystkie bazy danych,
     *
     * @return - true - jeśli silnik został zatrzymany i wszystkie bazy zostały
     * zamknięte, false - w przeciwnym przypadku.
     */
    public static boolean shutdownDerbyEngine() {
        boolean shutted;
        boolean gotSQLExc = false;
        try {
            DriverManager.getConnection("jdbc:derby:;shutdown=true");
        } catch (SQLException se) {
            if (se.getSQLState().equals("XJ015")) {
                gotSQLExc = true;
            }
        }
        shutted = gotSQLExc;
        return shutted;
    }
}
Klasa MainDB
package bridge.db;
import java.sql.*;
class MainDB {
	private static final String baza = "C:\\Przyklady\\logdb";
	private static final String properties = "create=true";
	private static final String createTable = "CREATE TABLE logtable "
			+ "(id INT PRIMARY KEY, logdata VARCHAR (300))";
	private static final String insertData = "INSERT INTO logtable "
			+ "VALUES(1, 'Mirka logging'),(2, 'Ula logging'),(3, 'Jacek logging')";
	private static final String selectData1 = "SELECT * FROM logtable";
	private static final String selectData2 = "SELECT * FROM logtable "
			+ "WHERE id=2";
	public static void main(String[] args) {
		DerbyUtil.startDerbyEngine(DerbyUtil.embdriver);
		Connection conn = DerbyUtil.connectEmbeddedDB(baza, properties);
		Statement stat1 = null;
		Statement stat2 = null;
		Statement stat3 = null;
		Statement stat4 = null;
		ResultSet rs1 = null;
		ResultSet rs2 = null;
		try{
			stat1 = conn.createStatement();
			stat1.execute(createTable);
		} catch (SQLException e){
			e.printStackTrace();
		}
		try{
			stat2 = conn.createStatement();
			stat2.execute(insertData);
		} catch (SQLException e){
			e.printStackTrace();
		}
		try{
			stat3 = conn.createStatement();
			rs1 = stat3.executeQuery(selectData1);
			while(rs1.next()){
				System.out.println(rs1.getInt(1) + " | " + rs1.getString(2));
			}
		} catch (SQLException e){
			e.printStackTrace();
		}
		try{
			stat4 = conn.createStatement();
			rs2 = stat4.executeQuery(selectData2);
			while(rs2.next()){
				System.out.println(rs2.getInt(1) + " | " + rs2.getString(2));
			}
		} catch (SQLException e){
			e.printStackTrace();
		}
		DerbyUtil.close(rs1);
		DerbyUtil.close(rs2);
		DerbyUtil.close(stat1);
		DerbyUtil.close(stat2);
		DerbyUtil.close(stat3);
		DerbyUtil.close(stat4);
		DerbyUtil.close(conn);
		DerbyUtil.shutdownEmbeddedDB(baza);
		DerbyUtil.shutdownDerbyEngine();
	}
}

Pakiet impl

Klasa Client
package bridge.impl;
import bridge.message.EncryptedMessage;
import bridge.message.Message;
import bridge.localization.FileLogger;
import bridge.localization.Logger;
class Client {
    public static void main(String[] args) {
        Logger logger = new FileLogger();
        Message msg = new EncryptedMessage(logger);
        msg.message("Test Message");
    }
}

Pakiet localization

Klasa ConsoleLogger
package bridge.localization;
public class ConsoleLogger implements Logger {
    @Override
    public void log(String msg) {
        System.out.println(msg);
    }
}
Klasa FileLogger
package bridge.localization;
import java.io.*;
public class FileLogger implements Logger {
    @Override
    public synchronized void log(String msg) {
        stringToFile("log.txt", msg, true);
    }
    private static void stringToFile(String file, String str, boolean append) {
        BufferedWriter bw = null;
        FileWriter fw = null;
        File f = new File(file);
        try {
            fw = new FileWriter(f, append);
            bw = new BufferedWriter(fw);
            bw.write(str);
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close(fw);
            close(bw);
        }
    }
    private static void close(Writer w) {
        if (w != null) {
            try {
                w.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
Klasa Logger
package bridge.localization;
public interface Logger {
    void log(String msg);
}

Pakiet message

Klasa EncryptedMessage
package bridge.message;
import bridge.localization.Logger;
import crypto.szyfrcezara.SzyfrCezara;
public class EncryptedMessage implements Message {
    private final Logger logger;
    public EncryptedMessage(Logger logger) {
        this.logger = logger;
    }
    @Override
    public void message(String msg) {
        String str = SzyfrCezara.encodeMessage(msg,13);
        logger.log(str);
    }
}
Klasa HTMLMessage
package bridge.message;
import bridge.message.Message;
import bridge.localization.Logger;
public class HTMLMessage implements Message {
    private final Logger logger;
    public HTMLMessage(Logger logger) {
        this.logger = logger;
    }
    @Override
    public void message(String msg) {
        String str = preprocess(msg);
        logger.log(str);
    }
    private String preprocess(String msg) {
        StringBuilder sb = new StringBuilder();
        sb.append("<html>");
        sb.append("<body>");
        sb.append("<strong>");
        sb.append(msg);
        sb.append("/strong");
        sb.append("/body");
        sb.append("</html>");
        return sb.toString();
    }
}
Klasa Message
package bridge.message;
public interface Message {
    void message(String msg);
}
Klasa TextMessage
package bridge.message;
import bridge.localization.Logger;
public class TextMessage implements Message {
    private final Logger logger;
    public TextMessage(Logger logger) {
        this.logger = logger;
    }
    @Override
    public void message(String msg) {
        String str = preprocess(msg);
        logger.log(str);
    }
    private String preprocess(String msg) {
        return msg;
    }
}

Wynik


Uwagi

Plik derby.jar możesz znaleźć tutaj. Ściągnij jeden z zaznaczonych plików. Po rozpakowaniu znajdziesz potrzebną bibliotekę.


Rys. 147. Pliki do ściągnięcia

Wzorzec Brigde jest zaprojektowany tak, aby odseparować interfejs klasy od jego
implementacji. Dzięki temu można zmieniać implementacje bez potrzeby wprowadzania zmian w kodzie, który korzysta z klasy.
W pakiecie db obok klasy DBLogger, zawierającej metodę writeToDB do napisania znajdują się klasy pomagające napisać taka metodę. Klasa MainDB pokazuje utworzenie, zapisanie i pobranie bazy logów. Twoim zadaniem jest rozdzieleni kodu i napisanie metody tworzącej bazę oraz metody zapisującej do bazy, a także metody wyświetlającej dane z bazy. Jedynym założeniem kodu jest, że na dysku C: istnieje folder C:/Przyklady. Dodatkowo umieszczona została klasa DerbyUtil zawierająca kod niezbędny do uruchomienia klasy MainDB.
W klasie EncryptedMessage wykorzystujemy szyfr Cezara przedstawiony we wpisie Szyfr Cezara

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *