SHOW:
|
|
- or go back to the newest paste.
1 | Beispiel aus der Übung: Model-View-Controller | |
2 | package bier.model; | |
3 | ||
4 | import java.util.NoSuchElementException; | |
5 | import java.util.Observable; | |
6 | ||
7 | /* | |
8 | * Model/Geschaeftslogik der Applikation. Observer | |
9 | * (View und evtl. Controller) koennen auf Aenderungen an dem Model horchen. | |
10 | */ | |
11 | public class Biertheke extends Observable { | |
12 | ||
13 | private int bier; | |
14 | private int groesse; | |
15 | ||
16 | public Biertheke(int groesse) { | |
17 | this.groesse = groesse; | |
18 | this.bier = 0; | |
19 | } | |
20 | ||
21 | public void zapfen() { | |
22 | ||
23 | if (istVoll()) { | |
24 | throw new IllegalStateException("Theke ist voll!"); | |
25 | } | |
26 | bier++; | |
27 | /* | |
28 | * Wenn sich das Model aendert, benachrichtigt es seine Observer. Wichtig: | |
29 | * Nur wenn setChanged() aufgerufen wurde, werden die Observer durch | |
30 | * notifyObservers() benachrichtigt. | |
31 | */ | |
32 | this.setChanged(); | |
33 | this.notifyObservers(); | |
34 | } | |
35 | ||
36 | public void verkaufen() { | |
37 | if (istLeer()) { | |
38 | throw new NoSuchElementException("Wir liegen trocken!"); | |
39 | } | |
40 | bier--; | |
41 | ||
42 | this.setChanged(); | |
43 | this.notifyObservers(); | |
44 | } | |
45 | ||
46 | public int getAnzahlBiere() { | |
47 | return this.bier; | |
48 | } | |
49 | ||
50 | public int getThekengroesse() { | |
51 | return this.groesse; | |
52 | } | |
53 | ||
54 | public boolean istVoll() { | |
55 | return bier == groesse; | |
56 | } | |
57 | ||
58 | public boolean istLeer() { | |
59 | return bier == 0; | |
60 | } | |
61 | ||
62 | } | |
63 | package bier.view; | |
64 | ||
65 | import bier.controller.ThekenController; | |
66 | import bier.model.Biertheke; | |
67 | ||
68 | import javax.swing.*; | |
69 | import java.awt.*; | |
70 | import java.util.Observable; | |
71 | import java.util.Observer; | |
72 | ||
73 | /* | |
74 | * View als spezieller Container. Hier JPanel, damit ein bestimmtes Layout zum | |
75 | * Anordnen der Elemente vorgegeben werden kann. Anderer Ansatz: Eine Klasse | |
76 | * 'baut' die View zusammen und liefert sie als ganzes zurueck. | |
77 | */ | |
78 | public class BierView extends JPanel implements Observer { | |
79 | ||
80 | private JButton bier; | |
81 | private JLabel counter; | |
82 | ||
83 | private Biertheke model; | |
84 | ||
85 | public BierView(Biertheke model) { | |
86 | /* | |
87 | * die View an das Model anhaengen | |
88 | */ | |
89 | this.model = model; | |
90 | this.model.addObserver(this); | |
91 | ||
92 | /* | |
93 | * die View bekommt ein Layout zugewiesen. andere interessante Layouts | |
94 | * sind CardLayout GridLayout FlowLayout | |
95 | */ | |
96 | this.setLayout(new BorderLayout()); | |
97 | ||
98 | /* | |
99 | * einen button mit bevorzugter Groesse erstellen | |
100 | */ | |
101 | this.bier = new JButton("Bier!"); | |
102 | this.bier.setPreferredSize(new Dimension(100, 100)); | |
103 | /* | |
104 | * Hiermit kann der Button ausgegraut werden | |
105 | */ | |
106 | this.bier.setEnabled(true); | |
107 | ||
108 | /* | |
109 | * View erzeugt Controller und haengt ihn ein | |
110 | */ | |
111 | ThekenController c = new ThekenController(this.model); | |
112 | this.bier.addMouseListener(c); | |
113 | ||
114 | /* | |
115 | * Label zur Darstellung erzeugen | |
116 | */ | |
117 | this.counter = new JLabel("Anzahl der Biere: "); | |
118 | ||
119 | /* | |
120 | * untergeordnete Elemente in dieser View nach den Moeglichkeiten des | |
121 | * Layouts anordnen. | |
122 | */ | |
123 | this.add(this.bier, BorderLayout.SOUTH); | |
124 | this.add(this.counter, BorderLayout.NORTH); | |
125 | ||
126 | } | |
127 | ||
128 | /* | |
129 | * Wird aufgerufen, wenn sich das Model aendert. o waere in diesem Fall das | |
130 | * Model arg die Nachricht, dies es mit notifyObservers uebergeben hat | |
131 | */ | |
132 | @Override | |
133 | public void update(Observable o, Object arg) { | |
134 | ||
135 | /* | |
136 | * Aendere View nach den Vorgaben des Models | |
137 | */ | |
138 | this.counter.setText("Anzahl der Biere: " + this.model.getAnzahlBiere()); | |
139 | } | |
140 | } | |
141 | package bier.controller; | |
142 | ||
143 | import bier.model.Biertheke; | |
144 | ||
145 | import java.awt.event.MouseAdapter; | |
146 | import java.awt.event.MouseEvent; | |
147 | ||
148 | /* | |
149 | * horcht auf Benutzereingaben und verstaendigt das Model | |
150 | */ | |
151 | public class ThekenController extends MouseAdapter { | |
152 | ||
153 | private Biertheke model; | |
154 | ||
155 | public ThekenController(Biertheke model) { | |
156 | this.model = model; | |
157 | } | |
158 | ||
159 | @Override | |
160 | public void mouseClicked(MouseEvent e) { | |
161 | ||
162 | /* | |
163 | * Wenn Theke voll bzw. leer soll nicht mehr geklickt werden koennen. - | |
164 | * Oder gehoert das in die Geschaeftslogik? | |
165 | */ | |
166 | switch (e.getButton()) { | |
167 | case MouseEvent.BUTTON1: | |
168 | if (!this.model.istVoll()) { | |
169 | this.model.zapfen(); | |
170 | } | |
171 | break; | |
172 | case MouseEvent.BUTTON3: | |
173 | if (!this.model.istLeer()) { | |
174 | this.model.verkaufen(); | |
175 | } | |
176 | break; | |
177 | } | |
178 | ||
179 | } | |
180 | } | |
181 | package bier; | |
182 | ||
183 | import bier.model.Biertheke; | |
184 | import bier.view.BierView; | |
185 | ||
186 | import javax.swing.*; | |
187 | ||
188 | public class Bier { | |
189 | ||
190 | public static void main(String[] args) { | |
191 | ||
192 | /* | |
193 | * Erzeugt und verbindet Model und View. | |
194 | */ | |
195 | Biertheke model = new Biertheke(5); | |
196 | ||
197 | BierView view = new BierView(model); | |
198 | ||
199 | /* | |
200 | * starte View | |
201 | */ | |
202 | JFrame frame = new JFrame("Biertheke"); | |
203 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
204 | frame.setContentPane(view); | |
205 | ||
206 | frame.pack(); | |
207 | frame.setVisible(true); | |
208 | } | |
209 | } |