1 Востаннє редагувалося fed_lviv (26.02.2015 11:29:08)

Тема: Абстрактний клас чи можна щось краще?

Відразу вибачаюсь, за назву теми, не знаю, як краще назвати.
Проблема така: В програмі є два дерева (JTree) також є два вузли (TreeNode). Для кожного вузла пишу клас, який наслідується від DefaultMutableTreeNode. Вся різниця між класами: 1. Різні дані (різні запити до БД) 2. Кількість вузілв в головноних вузлах різна ("вузол"-"вузол"-"вузол"-"листок" інший "вузол"-"вузол"-"листок") . Тобто класи майже ідентичні, не бачу сенсу мати два класи, тому все, що приходить на розум це створення абстрактного класу MyNode з визначиними методами і тільки один метод буде абстрактним setData(). Підкажіть, як бути чи створювати абстрактний клас чи є кращий вихід?

class ObjectNode

package tree;

import main.ConnectWork;
import dialog.ExceptionDialog;

import javax.swing.tree.DefaultMutableTreeNode;

import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Клас для створення вузла дерева (район-тип об'єкта-адреса об'єкта)
 * 
 */
public class ObjectNode extends DefaultMutableTreeNode {

    /**
     * Створює вузол дерева з ім'ям
     * 
     * @param name
     *            ім'я головного вузла
     * */
    public ObjectNode(String name) {
        super(name);
        setData();
    }

    /**
     * Метод заповняє вузол даними
     * */
    private void setData() {
        loadArea();
        for (int i = 0; i < getChildCount(); i++) {
            DefaultMutableTreeNode area = (DefaultMutableTreeNode) getChildAt(i);
            loadType(area);
            for (int j = 0; j < area.getChildCount(); j++) {
                loadAdreess(area, (DefaultMutableTreeNode) area.getChildAt(j));
            }
        }
    }

    /**
     * Метод додає вузли до головного вузла
     * */
    private void loadArea() {
        String procedure = "CALL all_region ();";
        try (CallableStatement statement = ConnectWork.connect
                .prepareCall(procedure);) {
            ResultSet result = statement.executeQuery();
            while (result.next()) {
                add(new DefaultMutableTreeNode(result.getString(1)));
            }
        } catch (SQLException e) {
            new ExceptionDialog(ConnectWork.frame == null ? null
                    : ConnectWork.frame, null, e);
        }
    }

    /**
     * Метод додає вузли до вузла
     * 
     * @param area
     *            вузол до якого додають вузли
     * */
    private void loadType(DefaultMutableTreeNode area) {
        String procedure = "CALL all_type_object_in_region (?)";
        try (CallableStatement statement = ConnectWork.connect
                .prepareCall(procedure);) {
            statement.setString(1, area.toString());
            ResultSet result = statement.executeQuery();
            while (result.next()) {
                area.add(new DefaultMutableTreeNode(result.getString(1)));
            }
        } catch (SQLException e) {
            new ExceptionDialog(ConnectWork.frame == null ? null
                    : ConnectWork.frame, null, e);
        }
    }

    /**
     * Метод додає листки до вузла
     * 
     * @param area
     *            вузол
     * @param type
     *            вузол до якого додають листки
     * */
    private void loadAdreess(DefaultMutableTreeNode area,
            DefaultMutableTreeNode type) {
        String procedure = "CALL all_address_in_region_and_type (?, ?)";
        try (CallableStatement statement = ConnectWork.connect
                .prepareCall(procedure);) {
            statement.setString(1, area.toString());
            statement.setString(2, type.toString());
            ResultSet result = statement.executeQuery();
            while (result.next()) {
                type.add(new DefaultMutableTreeNode(result.getString(1)));
            }
        } catch (SQLException e) {
            new ExceptionDialog(ConnectWork.frame == null ? null
                    : ConnectWork.frame, null, e);
        }
    }

    /**
     * Метод перезавантажує (поновлює) вузол
     * */
    public void reload() {
        removeAllChildren();
        setData();
    }
}

class MotorNode

package tree;

import main.ConnectWork;
import dialog.ExceptionDialog;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Клас для створення вузла дерева (серія двигуна-тип двигуна)
 * 
 */
public class MotorNode extends DefaultMutableTreeNode {

    /**
     * Створює вузол дерева з ім'ям
     * 
     * @param name
     *            ім'я головного вузла
     * */
    public MotorNode(String name) {
        super(name);
        setData();
    }

    /** Метод заповняє вузол даними */
    private void setData() {
        loadSeries();
        for (int i = 0; i < getChildCount(); i++) {
            DefaultMutableTreeNode series = (DefaultMutableTreeNode) getChildAt(i);
            loadType(series);
        }
    }

    /**
     * Метод додає вузли до головного вузла
     * */
    private void loadSeries() {
        String procedure = "CALL all_series_motor ();";
        try (CallableStatement statement = ConnectWork.connect
                .prepareCall(procedure);) {
            ResultSet result = statement.executeQuery();
            while (result.next()) {
                add(new DefaultMutableTreeNode(result.getString(1)));
            }
        } catch (SQLException e) {
            new ExceptionDialog(ConnectWork.frame == null ? null
                    : ConnectWork.frame, null, e);
        }
    }

    /**
     * Метод додає листки до вузла
     * 
     * @param series
     *            вузол до якого додають листки
     * */
    private void loadType(DefaultMutableTreeNode series) {
        String procedure = "CALL all_type_motor_in_series (?)";
        try (CallableStatement statement = ConnectWork.connect
                .prepareCall(procedure);) {
            statement.setString(1, series.toString());
            ResultSet result = statement.executeQuery();
            while (result.next()) {
                series.add(new DefaultMutableTreeNode(result.getString(1)));
            }
        } catch (SQLException e) {
            new ExceptionDialog(ConnectWork.frame == null ? null
                    : ConnectWork.frame, null, e);
        }
    }

    /**
     * Метод перезавантажує (поновлює) вузол
     * */
    public void reload() {
        removeAllChildren();
        setData();
    }

    /**
     * Метод повертає шлях до вказаного двигуна
     * 
     * @param series
     *            серія двигуна
     * @param type
     *            тип двигуна
     * @return шлях до двигуна об'єкт класа TreePath
     * */
    public TreePath getPathToMotor(Object series, Object type) {
        DefaultMutableTreeNode nodeSeries = null;
        for (int i = 0; i < getChildCount(); i++) {
            nodeSeries = (DefaultMutableTreeNode) getChildAt(i);
            if (nodeSeries.toString().equals(series)) {
                break;
            }
        }
        DefaultMutableTreeNode nodeType = null;
        for (int i = 0; i < nodeSeries.getChildCount(); i++) {
            nodeType = (DefaultMutableTreeNode) nodeSeries.getChildAt(i);
            if (nodeType.toString().equals(type)) {
                break;
            }
        }
        Object[] arr = new Object[] { getRoot(), nodeSeries, nodeType };
        return new TreePath(arr);
    }
}

2

Re: Абстрактний клас чи можна щось краще?

Важко сказати... треба в задачу вникати і логіку використання класів:) Якщо в класів різні задачі тоді можна і так залишити. Якщо ж є багато дублюючого коду і в одному і в іншому класі, тоді можна зливати. Все залежить як згодом ви ці класи використовуєте. Найкращий варіант, якщо між класами є щось спільне, то це спільне винесте у абстрактний клас, а все інше реалізувати у класах нащадках.

3

Re: Абстрактний клас чи можна щось краще?

У вас змішані різні рівні абстракції, якщо я все правильно зрозумів. Вузол дерева не повинен знати ні про мотори, ні про адреси, він знає тільки про предка і нащадків.

2. Кількість вузілв в головноних вузлах різна ("вузол"-"вузол"-"вузол"-"листок" інший "вузол"-"вузол"-"листок")

Цього моменту не зрозумів. В кожного вузла в загальному випадку різна кількість дітей. Це не робить ці вузли сутностями різних типів.

4 Востаннє редагувалося fed_lviv (26.02.2015 14:34:32)

Re: Абстрактний клас чи можна щось краще?

quez написав:

Цього моменту не зрозумів. В кожного вузла в загальному випадку різна кількість дітей. Це не робить ці вузли сутностями різних типів.

Можливо погано описав. Гм..... Якщо намалювати, то щось отаке:

Post's attachments

1.jpg 8.83 kb, 326 downloads since 2015-02-26 

5

Re: Абстрактний клас чи можна щось краще?

Наразі обійшовся без абстрактного класу, зробив один клас. Але ось ця перевірка "муляє очі"

if (procedures.length > 2)

Ось, що вийшло:

package tree;

import main.ConnectWork;
import dialog.ExceptionDialog;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Клас для створення вузла дерева
 * 
 */
public class MyNode extends DefaultMutableTreeNode {
    private final String[] procedures;

    /**
     * Створює вузол дерева з ім'ям
     * 
     * @param name
     *            ім'я головного вузла
     * @param procedures
     *             виклики SQL процедур
     * */
    public MyNode(String name, String[] procedures) {
        super(name);
        this.procedures = procedures;
        setData();
    }

    /** Метод заповняє вузол даними */
    private void setData() {
        addNode();
        for (int i = 0; i < getChildCount(); i++) {
            DefaultMutableTreeNode firstNode = (DefaultMutableTreeNode) getChildAt(i);
            addNode(firstNode);
            if (procedures.length > 2) {
                for (int j = 0; j < firstNode.getChildCount(); j++) {
                    addNode(firstNode,
                            (DefaultMutableTreeNode) firstNode.getChildAt(j));
                }
            }
        }
    }

    /**
     * Метод додає дочірні вузли до вузла
     * */
    private void addNode() {
        String procedure = procedures[0];
        try (CallableStatement statement = ConnectWork.connect
                .prepareCall(procedure);) {
            ResultSet result = statement.executeQuery();
            while (result.next()) {
                add(new DefaultMutableTreeNode(result.getString(1)));
            }
        } catch (SQLException e) {
            new ExceptionDialog(ConnectWork.frame == null ? null
                    : ConnectWork.frame, null, e);
        }
    }

    /**
     * Метод додає дочірні вузли до вузла
     * 
     * @param firstNode
     *            вузол до якого додають листки
     * */
    private void addNode(DefaultMutableTreeNode firstNode) {
        String procedure = procedures[1];
        try (CallableStatement statement = ConnectWork.connect
                .prepareCall(procedure);) {
            statement.setString(1, firstNode.toString());
            ResultSet result = statement.executeQuery();
            while (result.next()) {
                firstNode.add(new DefaultMutableTreeNode(result.getString(1)));
            }
        } catch (SQLException e) {
            new ExceptionDialog(ConnectWork.frame == null ? null
                    : ConnectWork.frame, null, e);
        }
    }

    /**
     * Метод додає дочірні вузли до вузла
     * 
     * @param firstNode
     *            вузол
     * @param secondNode
     *            вузол до якого додають листки
     * */
    private void addNode(DefaultMutableTreeNode firstNode,
            DefaultMutableTreeNode secondNode) {
        String procedure = procedures[2];
        try (CallableStatement statement = ConnectWork.connect
                .prepareCall(procedure);) {
            statement.setString(1, firstNode.toString());
            statement.setString(2, secondNode.toString());
            ResultSet result = statement.executeQuery();
            while (result.next()) {
                secondNode.add(new DefaultMutableTreeNode(result.getString(1)));
            }
        } catch (SQLException e) {
            new ExceptionDialog(ConnectWork.frame == null ? null
                    : ConnectWork.frame, null, e);
        }
    }

    /**
     * Метод перезавантажує (поновлює) вузол
     * */
    public void reload() {
        removeAllChildren();
        setData();
    }

    /**
     * Метод повертає шлях до вузла
     * 
     * @param firstNode
     *            вузол
     * @param type
     *            дочірній вузол
     * @return шлях до вузла об'єкт класа TreePath
     * */
    public TreePath getPathToList(Object firstNode, Object list) {
        DefaultMutableTreeNode first = null;
        for (int i = 0; i < getChildCount(); i++) {
            first = (DefaultMutableTreeNode) getChildAt(i);
            if (first.toString().equals(firstNode)) {
                break;
            }
        }
        DefaultMutableTreeNode second = null;
        for (int i = 0; i < first.getChildCount(); i++) {
            second = (DefaultMutableTreeNode) first.getChildAt(i);
            if (second.toString().equals(list)) {
                break;
            }
        }
        Object[] arr = new Object[] { getRoot(), first, second };
        return new TreePath(arr);
    }
}

6

Re: Абстрактний клас чи можна щось краще?

Вам без цеї перевірки скоріше всього не обійтись. Інша справа, що замість масиву з процедурами можна мати дві стрінгові змінні procedureToAddNodes та procedureToAddLeafs. Тоді перевірка буде нагляднішою.

А ще варто подумати, чи можна і чи варто винести і роботу з sql за межі цього класу

7

Re: Абстрактний клас чи можна щось краще?

quez написав:

Вам без цеї перевірки скоріше всього не обійтись. Інша справа, що замість масиву з процедурами можна мати дві стрінгові змінні procedureToAddNodes та procedureToAddLeafs. Тоді перевірка буде нагляднішою.

Якщо без масиву то взагалі можна зробити два методи setData()
setData(String toAddNode, String toAddLeaf)
setData(String toAddNodeFirst, String toAddNodeSecond, String toAddLeaf)
І тоді не потрібна буде перевірка масиву на розміри, але не хочеться робити два методи бо код буде збільшуватися.

8

Re: Абстрактний клас чи можна щось краще?

fed_lviv написав:
quez написав:

Цього моменту не зрозумів. В кожного вузла в загальному випадку різна кількість дітей. Це не робить ці вузли сутностями різних типів.

Можливо погано описав. Гм..... Якщо намалювати, то щось отаке:

Це точно дерева? Можете намалювати зв'язки між нодами?

9

Re: Абстрактний клас чи можна щось краще?

Точно дерево.
https://replace.org.ua/misc.php?action=pun_attachment&amp;item=753

Post's attachments

1.jpg 20.25 kb, 346 downloads since 2015-02-26 

10

Re: Абстрактний клас чи можна щось краще?

fed_lviv написав:

Точно дерево.

Ні, ну формально це дерево, так.

Але якщо у кожного з вузлів є лише один нащадок, то така структура описується зв'язним списком набагато краще.

Подякували: leofun011

11 Востаннє редагувалося fed_lviv (26.02.2015 16:14:20)

Re: Абстрактний клас чи можна щось краще?

Ні, нащадок не один, я намалював простий варіант для порівняння двох дерев. Щоб була видна різниця між деревами.