Objektorientierung - wie macht man's richtig?

Status
Nicht offen für weitere Antworten.

muemmel_0811

Bekanntes Mitglied
Hallo zusammen,
ich versuche gerade das mit der Objektorientierung verstehen zu lernen, aber irgendwie klappt das noch nicht so ganz und daher bräuchte ich mal wieder Eure Hilfe 🙂
Ich hab mir jetzt erstmal Tage lang den Kopf darüber zerbrochen, was ich denn so in meinen kleinen Progrämmchen überhaupt als Objekt identifizieren könnte und da ist mir dann ein "Verzeichnisläufer" eingefallen. Also etwas, dass best. Ordner incl. Unterordner nach irgendwelchen Dateien durchsucht und diese (also die Pfadangaben) in einer ArrayList speichert - für den Anfang reicht mir hier "irgendwelche Dateien" - ein Dateifilter folgt später.

Meine Frage ist jetzt, wie organisier ich das richtig. Ich hab gelernt, dass eine Klasse definiert, was ein Objekt weiß und was ein Objekt macht. Aber was weiß meine Klasse DirScan denn jetzt wirklich, welches sind ihre Instanzvariablen und welche Methoden gehören zu diesem Objekt?
Folgendes kleine Beispiel-Programm hab ich mal zusammengebastelt:
Klasse DirScan_Test
Code:
package pack;
import java.awt.BorderLayout;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class DirScan_Test extends JFrame{
	private static final long serialVersionUID = 1L;
	JTabbedPane tab = new JTabbedPane();
	Gui g = new Gui();
	DirScan_Test () {
		super();
		setTitle("Verzeichnis Scanner");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		initLaF();
		setLayout(new BorderLayout());
		tab.setFont(new Font("Verdana",Font.BOLD,11));
		tab.addTab("GUI", g);
		getContentPane().add(tab, BorderLayout.CENTER);
	}
	public void initLaF() {
		try {
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
			SwingUtilities.updateComponentTreeUI(this);
			SwingUtilities.updateComponentTreeUI(tab);
			SwingUtilities.updateComponentTreeUI(g);
		}
		catch(Exception c){
		}
	public static void main(String[] args) {
		JFrame f = new DirScan_Test();
		f.setSize(500,300); // 704
		f.setLocation(300,200);
		f.setVisible(true);
		f.setResizable(false);
	}
Klasse Gui
Code:
package pack;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Gui extends JPanel{
	private static final long serialVersionUID = 1L;
	JCheckBox optRekursiv = new JCheckBox("incl. Unterverzeichnisse", true);
	JLabel lblDir = new JLabel("Verzeichnis wählen");
	JTextField txtDir = new JTextField();
	JButton btnDir = new JButton("...");
	JButton btnGo = new JButton("Go");
	JTextArea taAusgabe = new JTextArea(7,10);
	JScrollPane scrAusgabe = new JScrollPane();
	Gui() {
		super();
		setLayout(null);
		lblDir.setBounds(10,10,200,20);
		lblDir.setFont(new Font("Verdana", Font.BOLD, 11));
		add(lblDir);
		txtDir.setBounds(10,30,350,20);
		txtDir.setFont(new Font("Courier New", Font.PLAIN, 14));
		add(txtDir);
		btnDir.setBounds(370,30,50,20);
		btnDir.setFont(new Font("Verdana", Font.BOLD, 11));
		add(btnDir);
		btnDir.addActionListener(new GetDir());
		btnGo.setBounds(430,30,50,20);
		btnGo.setFont(new Font("Verdana", Font.BOLD, 11));
		add(btnGo);
		btnGo.addActionListener(new StartRunDir());
		scrAusgabe.setBounds(10,60,470,160);
		scrAusgabe.setViewportView(taAusgabe);
		add(scrAusgabe);
	}
	class GetDir implements ActionListener{
		public void actionPerformed(ActionEvent ae) {
			JFileChooser fc = new JFileChooser();
			fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			int option = fc.showOpenDialog(txtDir);
			if(option == JFileChooser.APPROVE_OPTION) {
				String pfad = fc.getSelectedFile().getAbsolutePath();
				txtDir.setText(pfad);
			}
		}
	}
	class StartRunDir implements ActionListener{
		public void actionPerformed(ActionEvent ae) {
			DirScan ds = new DirScan();
			ds.setPfad(txtDir.getText());
			ArrayList<File> dateien = ds.runDir();
		}
	}
}
Klasse DirScan
Code:
package pack;
import java.io.File;
import java.util.ArrayList;
public class DirScan {
	private String pfad;
	private ArrayList<File> dateien = new ArrayList<File>();
	public void setPfad(String p) {
		pfad = p;
	}
	String getPfad() {
		return pfad;
	}
	ArrayList<File> runDir() {
		String tmp = getPfad();
		String fPfad = tmp.replaceAll("\\\\","\\\\\\\\");
		File f = new File(fPfad);
		ArrayList<File> al = spider(f);
		return al;
	}
	ArrayList<File> spider(File dir) {
		File[] verz = dir.listFiles();
		if(verz != null) {
			for(int i=0; i<verz.length; i++) {
				if(verz[i].isDirectory()) {
					spider(verz[i]);
				}
				if(verz[i].isFile()) {
					dateien.add(verz[i]);
				}
			}
		}
		return dateien;
	}
}
Es funktioniert, es tut was es soll - aber wie ist das nu mit der Objektorientierung? Was hab ich falsch gemacht, was könnte man wie verbessern?

Helft mir, damit ich es mal wirklich verstehen lerne!

Danke und Grüße,
muemmel
 
Schon ganz gut (bis auf den Namen... Buchstaben kosten nichts, nenn das z.B. "DirectoryScanner"), aber ich würde sagen, dass ein DirScan für einen Pfad gedacht ist.

Das hätte auch den Vorteil, dass du die Ergebnisse zwischenspeichern kannst.

"runDir" und "spider" würde ich private machen, "getPath" public und "setPath" löschen.

Am Schluss kommt dann sowas raus:

Code:
package pack;

import java.io.File;
import java.util.ArrayList;

public class DirScan {
	private String pfad;
	private ArrayList<File> dateien = null;

	public DirScan( String path ){
		if( path == null )
			throw new IllegalArgumentException( "path == null" );
		this.pfad = path;
	}

	public String getPfad() {
		return pfad;
	}

	public List<File> getDateien(){
		if( dateien == null )
			dateien = runDir();

		return dateien;
	}

	private ArrayList<File> runDir() {
		String tmp = getPfad();
		String fPfad = tmp.replaceAll("\\\\","\\\\\\\\");
		File f = new File(fPfad);
		return spider(f);
	}

	private ArrayList<File> spider(File dir) {
		File[] verz = dir.listFiles();
		if(verz != null) {
			for(int i=0; i<verz.length; i++) {
				if(verz[i].isDirectory()) {
					spider(verz[i]);
				}
				if(verz[i].isFile()) {
					dateien.add(verz[i]);
				}
			}
		}
		return dateien;
	}
}
 
Hallo Beni,

erstmal vielen Dank für Dein kleines Lob und auch für Deine Mühe, mir unter die Arme zu greifen :applaus:
Mit Deinen Änderungsvorschlägen sieht mein Code dann so aus:
Code:
package pack;
import java.io.File;
import java.util.ArrayList;
public class DirectoryScanner {
	private String pfad;
	private ArrayList<File> dateien = null;

	public DirectoryScanner(String path){
		if(path == null) {
			this.pfad = path;
			throw new IllegalArgumentException("path == null");
		}
		else {
			this.pfad = path;
		}
	}
	public String getPfad() {
		return pfad;
	}

	public ArrayList<File> getDateien(){
		if(dateien == null) {
			dateien = runDir();
		}
		return dateien;
	}

	private ArrayList<File> runDir() {
		String tmp = getPfad();
		String fPfad = tmp.replaceAll("\\\\","\\\\\\\\");
		File f = new File(fPfad);
		ArrayList<File> al = spider(f);
		return al;
	}

	private ArrayList<File> spider(File dir) {
		File[] verz = dir.listFiles();
		if(verz != null) {
			for(int i=0; i<verz.length; i++) {
				if(verz[i].isDirectory()) {
					spider(verz[i]);
				}
				if(verz[i].isFile()) {
					dateien.add(verz[i]);
				}
			}
		}
		return dateien;
	}
}

Auszug der Klasse Gui
Code:
...
class StartRunDir implements ActionListener{
   public void actionPerformed(ActionEvent ae) {
      DirectoryScanner ds = new DirectoryScanner(txtDir.getText());
	ArrayList<File> dateien = ds.getDateien();
   }
}
...

Aber ich hätte dann da jetzt doch noch ein paar Fragen:

wieso private ArrayList<File> dateien = null; - was ist daran besser, anders (oder was auch immer) als an private ArrayList<File> dateien = new ArrayList<File>(); ?

Worin liegt der Vorteil, der Variablen pfad ihren Wert über den Konstruktor der Klasse DirectoryScanner mitzuteilen ggü. der set-Methode?

Wieso ist es besser die Methode getDateien zu "erschaffen", wenn ich doch auch die Methode runDir als public deklarieren kann? Ich sehe keinen Unterschied darin, ob nun Methode A oder B public ist *grübl*
Das man spider besser als private macht, versteh ich, denn ich brauch diese Methode ja nicht außerhalb von DirectoryScanner, aber warum getDateien und nicht runDir...

Danke Dir und viele Grüße,
muemmel
 
wieso private ArrayList<File> dateien = null; - was ist daran besser, anders (oder was auch immer) als an private ArrayList<File> dateien = new ArrayList<File>(); ?
Wenn man die Dateien erst später lädt und das Ergebnis speichert (wie in meinem Vorschlag), kann man mit "null" sehr einfach sagen, dass da noch was fehlt. Hingegen kann man mit einer leeren Liste nicht so sicher sein, ob das jetzt schon geladen ist (und es einfach nichts zu sehen gibt), oder ob da noch nichts geladen ist.

Ich sehe aber gerade, dass du "dateien" auch in "spider" benutzt, da müsste man also noch sicherstellen, dass "dateien" nicht mehr null ist wenn "spider" aufgerufen wird (aber das ist ja nur eine neue Zeile z.B. in "runDir").

Da fällt mir ein: wieso gibt "spider" überhaupt etwas zurück, auf das du sowieso schon Zugriff hast? Etwas doppelspurig das ganze, spider könnte man auch "void" machen.

Worin liegt der Vorteil, der Variablen pfad ihren Wert über den Konstruktor der Klasse DirectoryScanner mitzuteilen ggü. der set-Methode?
Der Pfad kann so nicht mehr verändert werden. Ob es wichtig ist, dass der Pfad unveränderlich ist? Ich denke nicht, persönlich finde ich es einfach überflüssig den Pfad veränderlich zu haben (ist komplizierter und eine potentielle Fehlerquelle). Aber das ist so eine Entscheidung über die man stundenlang streiten könnte...

Wieso ist es besser die Methode getDateien zu "erschaffen", wenn ich doch auch die Methode runDir als public deklarieren kann? Ich sehe keinen Unterschied darin, ob nun Methode A oder B public ist *grübl*
Das man spider besser als private macht, versteh ich, denn ich brauch diese Methode ja nicht außerhalb von DirectoryScanner, aber warum getDateien und nicht runDir...
Wenn du bei deinem aktuellen Code "runDir" zweimal aufrufst, wird die ganze Verzeichnisstruktur zweimal durchlaufen (und da du die "dateien" niergends leerst, Dateien doppelt aufgeführt :bae: ).
Die Methode "getDateien" wirkt als Buffer der sicherstellt, dass nicht zuviel Arbeit ausgeführt wird - insbesondere dass die "teure" Operation "runDir" nur einmal aufgerufen wird.
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben