Zielony Smok - logo witryny

Wzorzec projektowy Composite (Java)

Zadanie programistyczne:

Stworzyć strukturę drzewiasta do opisania na przykład:

– układu folderów i zawartych w nich plików

– struktury zatrudnienia w firmie: szef i podlegli pracownicy

– struktury wojskowej: dowódcy i żołnierze z których jeden jest liściem (np. pracownik) i nie może mieć podwładnych a drugi jest szefem i ma podwładnych.

Rozwiązanie:

  1. stworzyć klasę abstrakcyjna AbstractPracownik
  2. dodać klasę ‘gałęzi’ – Szef
  3. dodać klasę ‘liścia’ – Pracownik
  4. stworzyć klasę pozwalającą na pokazanie drzewka podległości – DrzewkoPodleglosci

Uwagi: Ten przykład jest silnie wzorowany na przykładzie z książki J. W. Coopera 2001. Java. Wzorce projektowe. Wyd. Helion, Gliwice.

Klasy

Klasa AbstractPracownik
package composite;

import java.util.Enumeration;
import java.util.NoSuchElementException;

public abstract class AbstractPracownik {
    protected String nazwisko;
    protected long pensja;
    protected Pracownik kierownik = null;
    protected boolean podwladny = true;

    public abstract long getPensja();

    public abstract String getNazwisko();

    public abstract boolean add(Pracownik pracownik) throws NoSuchElementException;

    public abstract void remove(Pracownik pracownik) throws NoSuchElementException;

    public abstract Enumeration<Pracownik> podwladni();

    public abstract Pracownik getPodwladny(String podwladny);

    public abstract long getPensje();

    public boolean jestPodwladnym() {
        return podwladny;
    }
}
DrzewkoPodleglosci
package composite;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Enumeration;

public class DrzewkoPodleglosci extends JFrame implements TreeSelectionListener {
    private static final long serialVersionUID = 4432519732860863315L;
    Pracownik prac1, prac2, prac3;
    Pracownik prac4, prac5;
    Pracownik prac6, prac7;
    JScrollPane sp;
    JPanel treePanel;
    JTree tree;
    DefaultMutableTreeNode troot;
    JLabel cost;

    public DrzewkoPodleglosci() {
        super("Drzewko podleglości");
        makeEmployees();
        String laf = UIManager.getSystemLookAndFeelClassName();
        try {
            UIManager.setLookAndFeel(laf);
        } catch (UnsupportedLookAndFeelException exc) {
            System.err.println("Ostrzeżenie: brak " + laf);
        } catch (Exception exc) {
            System.err.println("Błąd ładowania " + laf + ": " + exc);
        }
        setGUI();
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }

    // --------------------------------------
    private void setGUI() {
        treePanel = new JPanel();
        getContentPane().add(treePanel);
        treePanel.setLayout(new BorderLayout());
        sp = new JScrollPane();
        treePanel.add("Center", sp);
        treePanel.add("South", cost = new JLabel("          "));
        treePanel.setBorder(new BevelBorder(BevelBorder.RAISED));
        troot = new DefaultMutableTreeNode(prac1.getNazwisko());
        tree = new JTree(troot);
        tree.setBackground(Color.lightGray);
        loadTree(prac1);
        sp.getViewport().add(tree);
        setSize(new Dimension(200, 300));
        setVisible(true);
    }

    // ------------------------------------
    public void loadTree(Pracownik topDog) {
        DefaultMutableTreeNode troot;
        troot = new DefaultMutableTreeNode(topDog.getNazwisko());
        treePanel.remove(tree);
        tree = new JTree(troot);
        tree.addTreeSelectionListener(this);
        sp.getViewport().add(tree);
        addNodes(troot, topDog);
        tree.expandRow(0);
        repaint();
    }

    // --------------------------------------
    private void addNodes(DefaultMutableTreeNode pnode, Pracownik emp) {
        DefaultMutableTreeNode node;
        Enumeration<Pracownik> e = emp.podwladni();
        if (e != null) {
            while (e.hasMoreElements()) {
                Pracownik newEmp = e.nextElement();
                node = new DefaultMutableTreeNode(newEmp.getNazwisko());
                pnode.add(node);
                addNodes(node, newEmp);
            }
        }
    }

    // --------------------------------------
    private void makeEmployees() {
        prac1 = new Szef("Smok Marszałek", 200000);
        prac1.add(prac2 = new Szef("Dowódca Armii Ludowej", 100000));
        prac1.add(prac3 = new Szef("Dowódca Floty", 100000));
        prac2.add(prac4 = new Szef("Dowódca Robotów", 50000));
        prac2.add(prac5 = new Szef("Dowódca Tajnych Agentów", 50000));
        // add salesmen reporting to sales manager
        for (int i = 0; i < 5; i++)
            prac4.add(new Pracownik("Oficer " + i, rand_sal(30000)));
        prac5.add(new Pracownik("Smok 007", 20000));
        prac3.add(prac6 = new Szef("Dowodca Floty Morskiej", 40000));
        prac3.add(prac7 = new Szef("Dowodca Floty Powietrznej", 35000));
        // add manufacturing staff
        for (int i = 0; i < 4; i++)
            prac6.add(new Pracownik("Kapitan " + i, rand_sal(25000)));
        // add shipping clerks
        for (int i = 0; i < 3; i++)
            prac7.add(new Pracownik("Pilot " + i, rand_sal(20000)));
    }

    // --------------------------------------
    private long rand_sal(long salary) {
        return salary + (long) (Math.random() - 0.5) * salary / 5;
    }

    // --------------------------------------
    @Override
    public void valueChanged(TreeSelectionEvent evt) {
        TreePath path = evt.getPath();
        String selectedTerm = path.getLastPathComponent().toString();
        Pracownik emp = prac1.getPodwladny(selectedTerm);
        if (emp != null)
            cost.setText(Float.valueOf(emp.getPensje()).toString());
    }

    // --------------------------------------
    static public void main(String argv[]) {
        new DrzewkoPodleglosci();
    }
}
Pracownik
package composite;

import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Vector;

public class Pracownik extends AbstractPracownik {
    public Pracownik(String nazwisko, long pensja) {
        this.nazwisko = nazwisko;
        this.pensja = pensja;
        podwladny = true;
    }

    // --------------------------------------
    public Pracownik(Pracownik kierownik, String nazwisko, long pensja) {
        this.nazwisko = nazwisko;
        this.pensja = pensja;
        this.kierownik = kierownik;
        podwladny = true;
    }

    // --------------------------------------
    @Override
    public long getPensja() {
        return pensja;
    }

    // --------------------------------------
    @Override
    public String getNazwisko() {
        return nazwisko;
    }

    // --------------------------------------
    @Override
    public boolean add(Pracownik pracownik) throws NoSuchElementException {
        throw new NoSuchElementException("Brak podwładnych");
    }

    // --------------------------------------
    @Override
    public void remove(Pracownik pracownik) throws NoSuchElementException {
        throw new NoSuchElementException("Brak podwładnych");
    }

    // --------------------------------------
    @Override
    public Enumeration<Pracownik> podwladni() {
        Vector<Pracownik> v = new Vector<>();
        return v.elements();
    }

    // --------------------------------------
    @Override
    public Pracownik getPodwladny(String podwladny) throws NoSuchElementException {
        throw new NoSuchElementException("Bez potomków");
    }

    // --------------------------------------
    @Override
    public long getPensje() {
        return pensja;
    }

    // --------------------------------------
    public Pracownik getKierownik() {
        return kierownik;
    }
}
Szef
package composite;

import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Vector;

public class Szef extends Pracownik {
    final Vector<Pracownik> podwladni;

    public Szef(String nazwisko, long pensja) {
        super(nazwisko, pensja);
        podwladny = false;
        podwladni = new Vector<>();
    }

    // --------------------------------------
    public Szef(Pracownik kierownik, String nazwisko, long pensja) {
        super(kierownik, nazwisko, pensja);
        podwladny = false;
        podwladni = new Vector<>();
    }

    // --------------------------------------
    public Szef(Pracownik pracownik) {
        super(pracownik.getNazwisko(), pracownik.getPensja());
        podwladni = new Vector<>();
        podwladny = false;
    }

    // --------------------------------------
    @Override
    public boolean add(Pracownik pracownik) throws NoSuchElementException {
        podwladni.add(pracownik);
        return true;
    }

    // --------------------------------------
    @Override
    public void remove(Pracownik pracownik) throws NoSuchElementException {
        podwladni.removeElement(pracownik);
    }

    // --------------------------------------
    @Override
    public Enumeration<Pracownik> podwladni() {
        return podwladni.elements();
    }

    // --------------------------------------
    @Override
    public Pracownik getPodwladny(String podwladny) throws NoSuchElementException {
        Pracownik nowyPracownik = null;
        if (getNazwisko().equals(podwladny))
            return this;
        else {
            boolean znaleziony = false;
            Enumeration<Pracownik> pracownicy = podwladni();
            while (pracownicy.hasMoreElements() && (!znaleziony)) {
                nowyPracownik = pracownicy.nextElement();
                znaleziony = nowyPracownik.getNazwisko().equals(podwladny);
                if (!znaleziony) {
                    if (!nowyPracownik.jestPodwladnym()) {
                        nowyPracownik = nowyPracownik.getPodwladny(podwladny);
                    } else
                        nowyPracownik = null;
                    znaleziony = (nowyPracownik != null);
                }
            }
            if (znaleziony)
                return nowyPracownik;
            else
                return null;
        }
    }

    // --------------------------------------
    @Override
    public long getPensje() {
        long suma = pensja;
        for (int i = 0; i < podwladni.size(); i++) {
            suma += (podwladni.elementAt(i)).getPensje();
        }
        return suma;
    }
}

Wynik

Po uruchomieniu klasy DrzewkoPodleglosci otrzymamy na konsoli:

Drzewko podległości
Rys. 173. Drzewko podleglości