Best Practice Klassendesign / Code Conventions

kaoZ

Top Contributor
Kleine Frage am Rande , wie würdet ihr diese Klasse für eine JToolBar erstellen sprich zwecks Magic Strings / Number, Konstanten, Deklarationen und Definitionen , hier mal mein Ansatz :

Java:
package de.kaoz.components;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JToolBar;

public class SimpleToolBar extends JToolBar{
	private static final long serialVersionUID = 1L;
	
	final static Dimension FILLER = new Dimension(30, 0);
	final static String IMG_PATH = "img/";
	
	JButton saveBtn, searchBtn, fileBtn, clientBtn;
	JButton[] btns = {saveBtn, searchBtn, fileBtn, clientBtn};
	
	{
		saveBtn		 = new JButton("", new ImageIcon(IMG_PATH + "save.png"));
		searchBtn	 = new JButton("", new ImageIcon(IMG_PATH + "search.png"));
		fileBtn		 = new JButton("", new ImageIcon(IMG_PATH + "file.png"));
		clientBtn	 = new JButton("", new ImageIcon(IMG_PATH + "client.png"));
	}
	
	public SimpleToolBar() {
		setFloatable(false);
		setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.lightGray));
		setPreferredSize(new Dimension(0,45));
		addElements();
	}
	
	private void addElements(){
		addSeparator();
		add(fileBtn);
		add(saveBtn);
		add(searchBtn);
		add(clientBtn);
		
	}
	
	public void setListener(ActionListener listener){
		for (JButton btn : btns) {
			btn.addActionListener(listener);
		}
	}
}

über Vorschläge oder Tipps wäre ich dankbar 😉

So siehts im moment aus :



Ziel ist das ich dies nachher als Bestandteil der GUI über einen Controller ansteuern kann, reicht es dazu die Listener in einer Schleife zu setzen, und wer liefert letztdendlich die Funktionalität der Listener, das Model oder ?
 
Zuletzt bearbeitet:
Meiner Meinung nach, wäre es bei fünf Buttons einfacher für jeden Button eine eigene Methode zu schreiben, welche die Listener hinzufügt . Im Controller meldest du dann die Listener events an und rufst beim Action event die gewünschte Model-Methode auf.
Sonst müsstest du eine Art Action ID erstellen und sie im Controller erfragen. Wie das ganz genau geht weiß ich leider nicht auf Anhieb 🙂
 
Ich könnte ich das ganze per
Code:
.setActionCommand(String value)
; lösen.

und jedem Button ein ActionCommand zuweisen.

Ich realisiere den Listener der für die Toolbar zuständig sein soll, in einer Separaten Klasse, die Frage ist jetzt , um die Events zu behandeln die von den Buttons der Toolbar abgefeuert werden , müsste ich um dementsprechend auszuführende Aktionen durchführen zu können (OMG dieser Satz o0) in der Listener Klasse ja wiederrum eine Referenz auf den Controller halten , welcher ja letztendlich an die Methoden der View delegiert.


Ich hoffe das war halbwegs verständlich :lol:
 
Zuletzt bearbeitet:
Ich dachte an ungefähr so etwas:

Java:
                public Controler(){
		this.view = new View();
		this.model = new MidiModel();
		this.view.setListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(e.getActionCommand() == "saveBtn"){
					model.save();
				}
                //...
			}
		});
	}

Du rufst deine Listner direkt im Konstruktor auf. Alternativ erstellst du eine innere Listener Klasse im Controller die die Events behandelt. Das ist sogar schöner und macht mehr Sinn, wenn Listener ausserhalb des Controllers nicht verwendet werde(Fällt mir spontan nichts ein in dem dies der Fall wäre)
 
nehmen wír mal an ich würde den Listener als innere Klasse des Controllers realisieren.

variablen etc. sind hier nur fiktiv gewählt !

Java:
public class Controller{

 View v;
 Model m;

public Controller(){
 this.v = new View();
 this.m = new Model();
}

public class ToolbarListener implements ActionListener(){
 ....
}

}

dann hätte ich ja im Normalfall, und nicht private deklariert, die Möglichkeit aus der inneren Klasse (also dem Listener) auf die Globalen Variablen des Controllers zuzugreifen sprich auf die Methoden der View und die des Models :

Java:
public void actionPerformed(ActionEvent Event){

 int value = m.calculate(12,23);
 v.setResultText(value);
}

was mache ich nun aber wenn ich den Listener ebend nicht als innere Klasse definiere, sondern in einer Eigenen Klasse, die ggf. sogar in einem anderer Package mit anderen listenern liegt, z.B einem Listener für die JMenuBar, die ebenfalls in einer Extra Klasse definiert ist ?!

der Plan war eigentlich für jeden Bereich, toolbar, Menubar, mainPanel , sidepanel einen eigenen Listener in jeweils einer eigenen Klasse zu realisieren.
 
Zuletzt bearbeitet:
Ist mir schon klar geworden... Die Frage bleibt aber was du damit verfolgst eigene Listener-Klassen zu entwerfen. So wie ich das sehe werden Listener ja nur im Controller aufgerufen.
Bei deinem Beispiel würde ich Vorschlagen das über einen Observer zu probieren. ???:L
 
Ok, der Ansatz mit den in Separaten Klassen realisierten Listenern war eigentlich die Zuständigkeit auszulagern um den Code in den einzelnen Klassen nicht unnötig aufzublähen, klar das schafft natürlich auch zusätzliche Komplexität....

Da ich vorher noch nicht nach dem MVC Pattern gearbeitet habe hier mal zum Verständnis eine grade schnell zusammengebaute Struktur , ob ich es verstanden habe, ( hier noch ohne Observer )

Ich habe mal versucht es so Simpel wie möglich zu gestalten:

Model:
Java:
package mvcTest;

public class Model {
	
	public Model() {}
	
	public String manipulateInput(String input){
		return new String(input + " dies macht das Model.");
	}

}

View:
Java:
package mvcTest;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

public class View extends JFrame {
	private static final long serialVersionUID = 1L;
	
	JButton btn ;
	JTextField txt;
	JLabel label;
	
	GridBagConstraints g;
	
	public View() {
		initialise();
		addComponents();
	}
	
	private void initialise(){
		txt = new JTextField();
		btn = new JButton("Abschicken");
		label = new JLabel();
		
		this.setLayout(new GridBagLayout());
		g = new GridBagConstraints();
		
		this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		this.setSize(300,150);
	}
	
	private void addComponents(){
		g.gridx = 0;
		g.gridy = 0;
		g.insets = new Insets(10,0,0,10);
		g.gridwidth = 1;
		g.fill = GridBagConstraints.HORIZONTAL;
		this.add(txt, g);
		
		g.gridx = 0;
		g.gridy = 1;
		this.add(btn, g);
		
		g.gridx = 0;
		g.gridy = 2;
		this.add(label, g);
	}
	
	public void setListener(ActionListener l){
		btn.addActionListener(l);
	}
	
	public String getTextInput(){
		return this.txt.getText();
	}
	
	public void setLabelText(String text){
		this.label.setText(text);
	}
	
	public void showFrame(){
		this.setVisible(true);
	}
}

Controller:
Java:
package mvcTest;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class Controller {
	
	View v;
	Model model;
	
	public Controller(Model model) {
		initialise(model);
		addListener();
	}
	
	public void showView(){
		v.showFrame();
	}
	
	private void initialise(Model model){
		this.v = new View();
		this.model = model;
	}
	
	private void addListener(){
		v.setListener(new ButtonListener());
	}
	

	// ---------------Inner Class Listner -------------------
	
	public class ButtonListener implements ActionListener{
		

		@Override
		public void actionPerformed(ActionEvent e) {
			if (e.getSource() == v.btn) {
				v.setLabelText(model.manipulateInput(v.getTextInput()));
			}
		}
	}

}

und zu guter letzt der Aufruf

Test:
Java:
package mvcTest;

public class Test {
	
	public static void main(String[] args) {
		new Controller(new Model()).showView();
	}

}

und so sähe das ganze dann im Zusammenspiel zu Testzwecken aus:



Hierzu dann noch ein paar Frage bzw. annahmen,

1. Kennt im Normalfall das Model den View ?

2. Das Model übernimmt ja nur Logische Aufgaben (bzw. die Logik) , in meinem Beispiel die einfache Manipulation des im View über den Controller , an das Model geleiteten Strings, angenommen ich müsste jetzt nur einen Text in ein Lable setzen ohne diesen weiter zu Manipulieren etc. wäre es nicht einfacher dieses direkt über den Controller zu regeln als an das Model weiterzuleiten ?

3. In der jetzigen Situation kennt der View weder das Model, noch den Controller, so wäre also Model und Controller, bzw. View gekapselt und austauschbar, im prinzip also vollkommen konform oder täusche ich mich ?

4. Der Controller Steuer über in View und Model bereitgestellte Methoden die Verarbeitung der Aktionen im View und die daraus resultierenden Aktionen und delegiert diese dann aus dem Model an den View.

5. Wie sähe jetzt das ganze mit der Implementierung des Observer-Patterns aus

danke schonmal für deine Mühen 🙂
 
Zuletzt bearbeitet:
Das ist ja immer so eine Sache wie weit man sich dran hält. 🙂
Also so wie ich das gelernt habe besteht zwischen Model und View keine Beziehung. Bzw. nur über Controller. Aber da werden wohl auch andere Meinung vertreten sein.
Deine zweite Frage verstehe ich nicht ganz, natürlich kannst du den Text setzten... sogar in der View. Dein Modell regelt ja die Funktionalität. Eventuelle Abhängigkeiten von anderen libs., initialisierungen von Streams etc etc... natürlich wäre die Implementation auch im Controller möglich, aber ob das MVC konform ist? Sobald ich das weiß ist die Idee das Model austauschbar ist.
Du hast eine update Methode in der View die aufgerufen wird sobald sich ein Observer-Object ändert, über notifyObeservers... Ich bin da jetzt selbst etwas unsicher aber sowas wie:

in der View:

Java:
public void update(Observer o, Object arg){
         label.setText((String) arg);
}

im Controller:

Java:
public void ActionPerformed(ActionEvent e){
           if(e.getActionCommand() == "saveBtn"){
                   notifyObservers("Text");
                }  
}

wobei, wie schon gesagt, über den Sinn oder Unsinn lässt sich hier jetzt streiten 😀
 
Laut der wiki beschreibung des MVC Konzeptes , sieht die Abhängigkeit so aus

Der Controller kennt logischer weise View und Model

Das Model kennt weder die View noch den Controller ( außer indirekt über Beobachter )

Die View kennt das Model ( und indirekt über einen Beobachter den Controller )

so interpretiert sich das zumindest aus folgender Grafik

350px-ModelViewControllerDiagram2.svg.png


Wer implementiert jetzt das Observer Interface ? der Controller ?

dann müsste ich ja zusätzlich noch Methoden anbieten um sich bei Beobachter als beobachtetes Subjekt einzutragen und ggf. bei Änderungen über
Code:
update();
benachrichtigt zu werden.

verstehe ich das soweit richtig ?
 
Zuletzt bearbeitet:

Zurück
Oben