Toon posts:

[JAVA] Design probleem

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met een java client/server schaakapplicatie.

Ik heb nu een bord wat tot op zeker hoogte werkt, en een stukje client/server wat ook werkt.

Ben nu bezig om dit in elkaar te schuiven.
Ik wil graag het client gedeelte van de client/server in een aparte klasse regelen => CommunicatieManager.java.
Deze maakt contact met een socket op de server, stuurt berichten en luistert naar berichten die ervandaan komen.

In Board.java zit een methode move(doe een zet) deze verplaatst het stuk op mijn gui.
Ik zou in Board.java een CommunicationManager Object kunnen aanmaken. Op het moment dat er een zet word gedaan, zou ik in move een methode aan kunnen roepen die een bericht stuurd naar de communicatieManager, die dat weer doorstuurd naar de server.

Tot zover duidelijk.
Maar die CommunicatieManager zit ook te luisteren naar zetten die van de andere kant komen, van de server dus.
Ik moet dus vanuit de CommunicatieManager ook de move functie van Board.java kunnen gebruiken. En CommunicatieManager weet (nog) niks van Board af.
Ik heb zelf 2 oplossingen:
1 - geef het Board object mee aan de constructor van CommunicatieManager. Lijkt me wel te werken, maar lijkt me geen nette oplossing al weet ik niet waarom.
2 - Maak gebruik van Observer/Observable

Mij lijkt Observer/Observable de beste oplossig, maar ik weet het niet zeker, of zijn er nog andere manieren?
En als 1 geen fatsoenlijke oplossing is, waarom dan?

Verwijderd

Ik zou voor 2 (observer pattern) gaan, al heb ik geen ervaring hoe je zoiets over netwerk connecties het beste kan doen.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 20-08 00:10
Mij lijken beide constructies wel geschikt. Het voordeel van de eerste is dat het makkelijk en overzichtelijk is; het nadeel is dat je klassen erg sterk aan elkaar koppelt en dus in de problem komt als je klassen zou willen hergebruiken of je ontwerp later wilt aanpassen.

De tweede optie heeft het genoemde nadeel niet, maar kost wat meer tijd en moeite om uit te denken. Voordeel is wel dat je met de tweede optie functionaliteit wat netter kunt scheiden en klassen echt kunt onkoppelen (dat laatste is natuurlijk het hoofddoel van het Observer pattern).

Je moet dus goednadenken over waar (in welke klassen) je functionaliteit onderbrengt en hoe je de communicatie tussen die onderdelen wilt regelen.

  • Eelke Spaak
  • Registratie: Juni 2001
  • Laatst online: 16-08 19:14

Eelke Spaak

- Vlad -

Een derde optie is de middenweg: zelf een soort van Observer/Observable structuur ontwerpen, die dan verder fungeert als de 1e optie. Deze optie heeft mijn persoonlijke voorkeur. Je kan een interface maken die de functies definiëert die een CommunicationManager zou moeten uitvoeren, en een interface voor het Board. Je huidige klassen noem je dan vervolgens MyCommManager en MyBoard (o.i.d.), en je laat je MyBoard een CommunicationManager (de interface dus) object maken, en de CommunicationManager interface specificeert dat 'ie een Board object wil meekrijgen als argument.

Op deze manier kan je nog heel makkelijk andere implementaties van de interfaces gebruiken, maar is het nog steeds flink wat overzichtelijker dan met de Observer/Observable constructie.

TheStreme - Share anything with anyone


Verwijderd

Het is misschien wel een leuke oefening om zelf netwerkcode te schrijven maar je zou RMI (Remote Method Invocation) kunnen gebruiken. Dan kan je de server aanspreken als een lokaal object en de server kan de client aanspreken als een lokaal object.
Enige dat je moet doen is een reference naar het remote object opvragen.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 20-08 00:10
Verwijderd schreef op 20 October 2003 @ 00:19:
Dan kan je de server aanspreken als een lokaal object en de server kan de client aanspreken als een lokaal object.
En RMI wordt geïmplementeerd door middel van een proxy pattern; met dat patroon zou je dus ook zelf iets soortgelijks kunnen implementeren.

Ik denk echter dat de ontwerpkeuze fundamenteler is; voordat je die proxy (van RMI of zelf gemaakt) kunt gebruiken moet je eerst je ontwerp hebben toegespitst op een omgeving waarin het invoeren van zetten mogelijk is voor meerdere objecten (in plaats van het ene bord object).

  • pgussow
  • Registratie: Maart 2003
  • Laatst online: 18-08-2025
Er is een 3de oplossing die ik zelf zou preferen:
Je maakt in Communication-object adaptermethods:
Java:
1
2
3
protected void onReceive(Message message)
{
}


In Board.java maak je een innerclass waarin je extend van CommunicationManager:
Java:
1
2
3
4
5
6
7
8
9
10
public class Board
{
    public class LocalCM extends CommunicationObject
    {
        protected void onReceive(Message message)
        {
            Board.this.doIetsMetMessage(message);
        }
    }
}


Het voordeel hier van is dat je communication-object niets van Board afweet. OO technisch is dat ook verantwoorder. Want Board gebruikt CM. En niet andersom. Met deze oplossing weet CM niets van Board en kun je dus CM ook voor andere dingen gebruiken

  • Eelke Spaak
  • Registratie: Juni 2001
  • Laatst online: 16-08 19:14

Eelke Spaak

- Vlad -

pgussow schreef op 20 oktober 2003 @ 08:18:
Er is een 3de oplossing die ik zelf zou preferen:
Je maakt in Communication-object adaptermethods:
Java:
1
2
3
protected void onReceive(Message message)
{
}


In Board.java maak je een innerclass waarin je extend van CommunicationManager:
Java:
1
2
3
4
5
6
7
8
9
10
public class Board
{
    public class LocalCM extends CommunicationObject
    {
        protected void onReceive(Message message)
        {
            Board.this.doIetsMetMessage(message);
        }
    }
}


Het voordeel hier van is dat je communication-object niets van Board afweet. OO technisch is dat ook verantwoorder. Want Board gebruikt CM. En niet andersom. Met deze oplossing weet CM niets van Board en kun je dus CM ook voor andere dingen gebruiken
Dat is dus ongeveer wat ik bedoelde, en inderdaad, inner classes maken is dan een mooiere oplossing dan wat ik zei.

Ik zou echter wel een interface CommunicationObject maken, en geen lege klasse. Een belangrijke reden (naast meervoudige overerving) voor interfaces is juist dat je dit soort subclassing van lege klassen niet meer nodig hebt :) .

TheStreme - Share anything with anyone


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Afgezien van het communicatie gedeelte (wat je bv fantastisch mbv een Proxy kan scheiden van een bepaalde middleware keuze), zit je ook nog met concurrency control (vooral als je bv met rmi of corba ofzo gaat werken). Iedere client object op de server leeft daar in zijn eigen thread, dus je loopt daar sowieso met concurrency control te klooien.

Als clients een relatief korte actie moeten uitvoeren zou je er bv ook voor kunnen kiezen om een queue te maken op de server waarin iedere client voor een bepaalde request een message in plaats (plus een verwijzing naar zichzelf). Dit gebeurt wel thread safe.

Daarna laat je de hoofdserver thread luisteren naar die queue om daar weer messages/requests uit te pakken om. Aangezien de message ook een referentie heeft naar de client, kan de server op het moment dat het voor hem goed uitkomt, weer contact opnemen met de client.

Deze server thread is eigelijk de enigste thread die op de server actief is en alle structuren mag aanspreken, dus het gevolg is dat je afgezien van die message queue totaal niet meer om concurrency control hoeft te denken.

Wat ik hier trouwens heb beschreven is een afgeslankte versie van de Reactor design pattern.

ps:
ik zou trouwens voor RMI ofzo gaan en niet voor sockets. Waarom zou je al dat low level werk willen verrichten als iemand anders dat al voor je kan doen :)

[ Voor 20% gewijzigd door Alarmnummer op 20-10-2003 12:50 ]


Verwijderd

Topicstarter
Die oplossing met die innerklasse ziet er erg sjiek uit _/-\o_ . daar ga ik eens mee aan de slag.

RMI is inderdaad waarschijnlijk een betere oplossing, maar het client/server gedeelte functioneert al, dus tenzij we straks tegen problemen aan lopen laten we dit nu zo.

Alarmnummer denkt al iets te ver, denk dat we het dan te moeilijk gaan maken. Dit is iets voor later.
Soultaker schreef op 20 October 2003 @ 02:31:
[...]

Ik denk echter dat de ontwerpkeuze fundamenteler is; voordat je die proxy (van RMI of zelf gemaakt) kunt gebruiken moet je eerst je ontwerp hebben toegespitst op een omgeving waarin het invoeren van zetten mogelijk is voor meerdere objecten (in plaats van het ene bord object).
Ik snap niet helemaal wat je hier bedoeld Soultaker.... :?
Bedoel je het ontwerp van het bord met de stukken etc. Dat is er nl al. Ik kan ook een stuk verplaatsen, alleen moet dit nu dus nu ook over het netwerk kunnen.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op 20 October 2003 @ 20:18:
Die oplossing met die innerklasse ziet er erg sjiek uit _/-\o_ . daar ga ik eens mee aan de slag.

RMI is inderdaad waarschijnlijk een betere oplossing, maar het client/server gedeelte functioneert al, dus tenzij we straks tegen problemen aan lopen laten we dit nu zo.

Alarmnummer denkt al iets te ver, denk dat we het dan te moeilijk gaan maken. Dit is iets voor later.
Als je met RMI gaat werken, leeft de client stub op de server in zijn eigen thread. Iedere aanroep die een client doet op de server vind dus op een eigen thread plaats binnen de server. Je komt dus automatisch in aanraking met een multi-threaded omgeving.

Je kan natuurlijk je ogen dichtdoen en hopen dat het maar goed gaat, maar je kan natuurlijk ook een oplossing maken die geen raar gedrag gaat vertonen.

ps: alles synchronized maken gaat niet werken -> deadlocks
Pagina: 1