Kihagyás

8. gyakorlat

A gyakorlat anyaga

Visitor

  • Cél: objektum-hierarchián végezhető művelet reprezentálása az osztályok megváltoztatása nélkül

  • Alkalmazhatóság:

  • több független műveletet kell elvégezni egy objektum-struktúrán (az osztályok "beszennyezése" nélkül)
  • a struktúrát meghatározó osztályok ritkán változnak, új műveleteket viszont sűrűn definiálhatunk

Példa

  • Composite mintánál vizsgált könyvtárszerkezet példája

  • Van két műveletünk:

  • Fa-szerkezet listázás

  • Könyvtárak és fájlok számának megszámolása
  • Két különböző műveletet számoljuk ki két különböző visitorral!
VisitableResource.java
1
2
3
4
5
public interface VisitableResource extends Resource {

    void accept(FileSystemVisitor visitor);

}
FileSystemVisitor.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public interface FileSystemVisitor {

    void visit(VisitableFolder folder);

    default void visitEnd(VisitableFolder folder) {
    }

    void visit(VisitableFile file);

}
VisitableFile.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class VisitableFile implements VisitableResource {

    private String name;
    private int size;

    public VisitableFile(String name, int size) {
        super();
        this.name = name;
        this.size = size;
    }

    @Override
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSize(int size) {
        this.size = size;
    }

    @Override
    public int getSize() {
        return this.size;
    }

    @Override
    public boolean isDirectory() {
        return false;
    }

    @Override
    public String toString() {
        return this.name;
    }

    @Override
    public void accept(FileSystemVisitor visitor) {
        visitor.visit(this);
    }

}
VisitableFolder.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import java.util.ArrayList;
import java.util.List;

public class VisitableFolder implements VisitableResource {

    private String name;
    private List<VisitableResource> resources = new ArrayList<>();

    public VisitableFolder(String name) {
        super();
        this.name = name;
    }

    public void addResource(VisitableResource resource) {
        this.resources.add(resource);
    }

    public List<VisitableResource> getResources() {
        return this.resources;
    }

    @Override
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int getSize() {
        int size = 0;
        for (VisitableResource resource : this.resources) {
            size += resource.getSize();
        }
        return size;
    }

    @Override
    public boolean isDirectory() {
        return true;
    }

    @Override
    public String toString() {
        return "[" + this.name + "]";
    }

    @Override
    public void accept(FileSystemVisitor visitor) {
        visitor.visit(this);
        for (VisitableResource child : this.getResources()) {
            child.accept(visitor);
        }
        visitor.visitEnd(this);
    }

}
TreePrinterVisitor.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class TreePrinterVisitor implements FileSystemVisitor {

    private int indent = 0;

    @Override
    public void visit(VisitableFolder folder) {
        this.printIndent();
        System.out.println(folder);
        this.indent += 2;
    }

    @Override
    public void visitEnd(VisitableFolder folder) {
        this.indent -= 2;
    }

    @Override
    public void visit(VisitableFile file) {
        this.printIndent();
        System.out.println(file);
    }

    private void printIndent() {
        for (int i = 0; i < this.indent; i++) {
            System.out.print(" ");
        }
    }

}
TypeCounterVisitor.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class TypeCounterVisitor implements FileSystemVisitor {

    private int folders = 0;
    private int files = 0;

    @Override
    public void visit(VisitableFolder folder) {
        this.folders++;
    }

    @Override
    public void visit(VisitableFile file) {
        this.files++;
    }

    public int getNumberOfFolders() {
        return this.folders;
    }

    public int getNumberOfFiles() {
        return this.files;
    }

    @Override
    public String toString() {
        return "Folders: " + this.folders + " Files: " + this.files;
    }

}
Client.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Client {

    public static void main(String[] args) {
        VisitableFolder root = new VisitableFolder("root");
        VisitableFolder dev = new VisitableFolder("dev");
        root.addResource(dev);
        VisitableFolder nul = new VisitableFolder("null");
        dev.addResource(nul);
        VisitableFolder user = new VisitableFolder("student");
        root.addResource(user);
        VisitableFile readme = new VisitableFile("readme.txt", 11);
        VisitableFile linux = new VisitableFile("debian.iso", 2048);
        user.addResource(readme);
        user.addResource(linux);
        VisitableFile welcome = new VisitableFile("motd", 200);
        root.addResource(welcome);

        TypeCounterVisitor tcv = new TypeCounterVisitor();
        root.accept(tcv);
        System.out.println(tcv);

        TreePrinterVisitor tpv = new TreePrinterVisitor();
        root.accept(tpv);
    }

}

Gondolatok

  • visit(), visitEnd() -> template method?

  • generikus visit() metódus, ami általános objektumot vár az UML-en látottak helyett (egy absztrakt osztályban)

  • Java esetében reflection segítségével jó tud lenni

Feladatok

  1. Az alábbiakban megtalálható a MusicLibraryExercise.java fájl. Tanulmányozzuk, alakítsuk át úgy, hogy legyen benne tervezési minta. Jelenlegi gondok?!
    • Minden műfajt egyesével szeretném kikérni (rap, classic, stb). Mindenre kéne egy getter? Egybemosódik az adatszerkezet és az algoritmusok.
    • Mi van akkor, ha szeretnék rap és rock zenéket keresni? Egyesével, majd a halmazokat egyesítem? Írjak rá külön egy metódust? Sehogy sem túl jó jelenleg…
    • Melyik minta lehet?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

interface Visitor<T> {
    void visit(Set<T> items);
}

class Music implements Comparable<Music>{
    public String artist;
    public String name;
    public String genre;
    boolean isCompactDisc;
    boolean isMusicDvd;

    public Music(String artist, String name, String genre) {
        this.artist = artist;
        this.name = name;
        this.genre = genre;
        this.isCompactDisc = false;
        this.isMusicDvd = false;
    }

    public Music(String name, String artist, String genre, boolean isCompactDisc, boolean isMusicDvd) {
        this.artist = artist;
        this.name = name;
        this.genre = genre;
        this.isCompactDisc = isCompactDisc;
        this.isMusicDvd = isMusicDvd;

    }


    @Override
    public String toString() {
        return String
                .format("Music [artist=%s, name=%s, genre=%s, isCompactDisc=%s, isMusicDvd=%s]", artist, name, genre, isCompactDisc, isMusicDvd);
    }

    @Override
    public int compareTo(Music o) {
        String tmp1 = this.artist + " " + this.name;
        String tmp2 = o.artist + " " + o.name;
        return tmp1.compareTo(tmp2);
    }

}

class MyMusicLibrary {
    private Set<Music> musicCollection = new TreeSet<Music>();

    public void add(Music m) {
        musicCollection.add(m);
    }

    public Set<Music> getRockMusic(){
        return this.musicCollection.stream().filter(m -> "rock".equalsIgnoreCase(m.genre)).collect(Collectors.toSet());
    }

    public Set<Music> getPopMusic(){
        return this.musicCollection.stream().filter(m -> "pop".equalsIgnoreCase(m.genre)).collect(Collectors.toSet());
    }

}

public class MusicLibraryExercise {
    public static void main(String[] args) {
        MyMusicLibrary library = new MyMusicLibrary();
        library.add(new Music("Thunderstruck", "AC/DC", "rock", false, false));
        library.add(new Music("Who Made Who", "AC/DC", "rock", false, false));
        library.add(new Music("Whole Lotta Rosie", "AC/DC", "rock", false, false));
        library.add(new Music("Growin Up", "Bruce Springsteen", "pop", false, false));
        library.add(new Music("Crossroads", "Cream", "pop", false, false));
        library.add(new Music("Jean Genie", "David Bowie", "rap", false, false));
        library.add(new Music("Boulevard Of Broken Dreams", "Green Day", "rap", false, false));
        library.add(new Music("Little Queen", "Heart", "folk", false, false));
        library.add(new Music("Nothing Is Easy", "Jethro Tull", "folk", false, false));
        library.add(new Music("All Along the Watchtower", "Jimi Hendrix", "indie", false, false));
        library.add(new Music("Wheel in the Sky", "Journey", "rock", false, false));
        library.add(new Music("Black Dog", "Led Zeppelin", "alternative", false, false));
        library.add(new Music("I'm Down", "The Beatles", "classic", false, false));
        library.add(new Music("No woman no cry", "Bob Marley", "raggae", false, false));
        library.add(new Music("Bridge Over Troubled Water", "Simon And Garfunkel", "punk", false, false));

        System.out.println(library.getRockMusic());
    }
}

Utolsó frissítés: 2021-11-17 11:01:33