Ewiges Leid mit "protected" (oder "wie der beste Freund eine hinrücks betrügt")

Status
Nicht offen für weitere Antworten.

Ford_Prefect

Mitglied
Hallo Java-Welt,

Zusammen mit einem Freund bin dabei ein kleines Spiel in Java zu entwickel und wir scheitern leider kläglich an der Kapselung eines wizigen Attributes - der Position.
In unserem Spiel braucht jedes Objekt eine Position auf dem Spielfeld, und die soll auch NUR von dem jeweiligen Objekt durch Methodenaufrufe verändert werden (nichts neues also...).

Hier einmal 4 Beispielklassen, die das Problem verdeutlichen:

Java:
class Spielobjekt{
   protected int position
...
}

Java:
class Kugel extends Spielobjekt{
   private int geschwindigkeit = 5;

   public void positionAktualisiren()
   {
   //Zugriff auf position von Spielobjekt
   position = position + geschwindigkeit;
   }
}

Java:
class Gegner extends Spielobjekt{

   public void angreifen(Spieler spieler)
   {
   //In Richtung des Spielers bewegen - also zugriff auf position nötig!!!
   }

}

Java:
class Spielfigur extends Spielobjekt{

   public void getroffenVon(Kugel kugel)
   {
   //Genau hier kann ich jetzt die Position von der Kugel beliebig ändern und das ist nicht im Sinne des Erfinders....
   kugel.position = 42;
   }
}

Wie können wir unbefugen Zugriff auf die Position verhinder, gleichzeitig aber allen Unterobjekten von Spielobjekt ermöglichen ihre Position zu verändern?

Ein einfacher (protected) Setter ist sicher auch nicht besser als das Attribut so zu lassen, da dann über einen kleinen Umweg genau das gleiche Erreicht werden kann...
Das ist sicherlich kein neues Problem, wäre also super wenn ihr eure Erfahrungen mit uns teilen könntet. Wir stehen da etwas auf dem Schlauch:bahnhof:
 

icarus2

Top Contributor
Ich bin mir jetzt nicht genau sicher was du meinst. Aber du könntest die Variable ja einfach als Private deklarieren. Über Methoden kannst du dann die Variable verändern. Wenn du von der Klasse ableitest allenfalls mit super.

Sowas hier vereinfacht:

[Java]
public class A {

public static void main(String[] args) {
B b = new B();

b.setPosition(25);

System.out.println(b.getPosition());
}
}

class B {

private int position = 10;

public void setPosition(int position){
this.position = position;
}

public int getPosition(){
return position;
}
}
[/Java]
 

neonfly

Aktives Mitglied
Aber du könntest die Variable ja einfach als Private deklarieren. Über Methoden kannst du dann die Variable verändern.

Das löst aber nicht sein Problem. Ob Methoden aufgerufen werden order die proVar direkt benutzt werden, das sind nur kleine Änderungen in der Zeile. Ich habe das so verstanden, dass es in bestimmten Klassen unmöglich sein soll, überhaupt darauf zu zu greifen (Spielfigur).

Vielleicht sollt die Klasse Spielobjekt noch weiter herunter gebrochen werden.

position = position + geschwindigkeit;
?
 

Ford_Prefect

Mitglied
Richtig, eigentlich soll niemand das Attribut (also hier die Position) ändern, außer der Klasse selbst. Das schreit ja eigentlich nach private...
Dann müsste ich aber für jede Subklasse immer wieder ein Attribut "position" anlegen und dagegen streube ich mich auch -.-
Wenn es allerdings üblich ist, so etwas in Java zu tun, dann mache ich das natürlich.


Package-Private macht so ich dass mit dem Modell sehe auch wenig sinn (schleches Design?)

position = position + geschwindigkeit
Soll einfach nur darstellen, dass auf position zugegriffen werden muss.
 

Noctarius

Top Contributor
Wie wäre es mit Package also dem Standard wenn du keine Angabe machst? Funktioniert selbstverständlich nur, wenn sich beide Klassen im selben Package befinden. Vielleicht hilft dir das weiter.
 

Michael...

Top Contributor
wenn ich das richtig verstanden habe könnte man das über die Package-Struktur regeln
Code:
+mainpackage
      +package1
            +Spielfigur
            +Kugel extends Spielfigur
      +package2
            +Gegner extends Spielfigur
Die Klasse Kugel würde dann eine Methode getPosition() benötigen, damit der Gegner die Position lesen kann.

Wenn ich allerding so darüber nachdenke, kommt man um ein private Member position nicht herum, da ja auch der Gegner eine Position haben muss.
 
S

SlaterB

Gast
ein Gedankengang, der vielleicht weder schön noch objektorientiert ist, der mir aber gerade einfiel:

die Methode setPosition bekommt noch einen zweiten Parameter mit dem sich auf Aufrufer authentifiziert,
das Kugelobjekt selber ist nicht so geeignet, jede Spielperson könnte
kugel.setPosition(kugel, 42);
aufrufen,
es müßte ein geheimes Objekt sein, welches jede Klasse für sich privat static definiert,
das muss einerseits an die Super-Klasse bekannt gemacht werden, darf aber sonst von außen nicht abfragbar sein

Java:
public class Test {

	public static void main(String argv[]) throws Exception {
		Kugel k = new Kugel();
		System.out.println("kugel: " + k.getPosition());
		k.positionAktualisiren();
		System.out.println("kugel: " + k.getPosition());
		Spielfigur s = new Spielfigur();
		System.out.println("figur: " + s.getPosition());
		s.getroffenVon(k);
		System.out.println("kugel: " + k.getPosition());
	}
}

class Spielobjekt {
	private int position = 4;

	private Object key;

	protected void setKey(Object key) {
		if (this.key == null) {
			this.key = key;
		} else {
			// evtl. Fehler melden..
		}
	}

	protected int getPosition() {
		return this.position;
	}

	protected void setPosition(Object key, int position) {
		if (this.key == key) {
			this.position = position;
		} else {
			// evtl. Fehler melden..
		}
	}

}

class Kugel extends Spielobjekt {

	private static final Object KEY = new Object();

	private int geschwindigkeit = 5;

	public Kugel() {
		setKey(KEY);
	}

	public void positionAktualisiren() {
		// Zugriff auf position von Spielobjekt
		setPosition(KEY, getPosition() + geschwindigkeit);
	}
}

class Spielfigur extends Spielobjekt {

	private static final Object KEY = new Object();

	public Spielfigur() {
		setKey(KEY);
	}

	public void getroffenVon(Kugel kugel) {
		// Genau hier kann ich jetzt die Position von der Kugel beliebig ändern
		// und das ist nicht im Sinne des Erfinders....
		kugel.setPosition(KEY, 42);
	}
}
wie gesagt bitte höchstens die Idee zur Kenntnis nehmen, nicht einbauen ;)

edit: wenn man die Klassen generisch macht und den Key auch,
dann bekommt man gleich ne Fehlermeldung im Compiler bei Angabe eines falschen Keys
 
Zuletzt bearbeitet von einem Moderator:

thE_29

Top Contributor
Ist zwar nicht die sauberste Lösung, aber immerhin funktioniert sie ;)

Java:
package at;

public class Gamer
{
  public Gamer()
  {
    super();
  }
  
  protected void setPosition(int pos) throws IllegalArgumentException
  {
    try{
      StackTraceElement trace[] = Thread.currentThread().getStackTrace();
      if(trace == null || trace.length < 3 || !Class.forName(trace[2].getClassName()).isAssignableFrom(this.getClass()))
        throw new IllegalArgumentException("JUST EXTENDED CLASSES ARE ALLOWED TO CALL THIS METHOD");
    }
    catch(Exception ex)
    {
      ex.printStackTrace(System.out);
      throw new IllegalArgumentException("JUST EXTENDED CLASSES ARE ALLOWED TO CALL THIS METHOD", ex);
    }
    System.out.println("SETZE POSITION AUF: " + pos);
  }
  
  public void testIt()
  {
    setPosition(1);
  }
}

Java:
package at;

public class ExtendedGamer extends Gamer
{
  public ExtendedGamer()
  {
    super();
  }
  
  public void testIt()
  {
    setPosition(65);
  }
}

Java:
package at.foreign;

import at.Gamer;

public class ExtendedForeignGamer extends Gamer
{
  public ExtendedForeignGamer()
  {
    super();
  }
  
  public void testIt()
  {
    setPosition(777);
  }
}

Java:
package at;

public class ForeignGamer
{
  public ForeignGamer()
  {
    super();
  }

  public void testIt()
  {
    Gamer gamer = new Gamer();
    gamer.setPosition(56);
  }
}

Java:
    new at.Gamer().testIt();
    new at.ExtendedGamer().testIt();
    new at.foreign.ExtendedForeignGamer().testIt();
    new at.ForeignGamer().testIt();

Liefert:
SETZE POSITION AUF: 1
SETZE POSITION AUF: 65
SETZE POSITION AUF: 777
java.lang.IllegalArgumentException: JUST EXTENDED CLASSES ARE ALLOWED TO CALL THIS METHOD
at at.Gamer.setPosition(Gamer.java:15)
at at.ForeignGamer.testIt(ForeignGamer.java:13)
at Test.<init>(Test.java:3717)
at Test.main(Test.java:5647)
 

Noctarius

Top Contributor
Ich bleib bei dem Ansatz es über die Packages zu regeln und die Subclasses ins selbe Package zu legen wie die Superclass und dann den Package-Modifier zu nutzen (ergo keinen anzugeben). Das ist sauber, sicher, objektorierentiert und mit 100% Sicherheit schneller als die If-Abfrage (jaja bis der Hotspot es wegoptimiert hat :D)
 

ARadauer

Top Contributor
Grundsätzlich geht es ja darum, dass ich normalerweise weis was ich mache, von dem her sind ja diese modifier nur eine wage hilfestellung.

Richtig Sinn macht es ja erst, wenn ich etwas protected, oder private defniere, wenn andere meinen Code benutzen und in diesem fall werden die höchstwahrscheinlich in einem anderen package liegen.

Also die Variante mit den Packages scheint mir am sinnvollsten.
 

Ford_Prefect

Mitglied
Sollte Java 7 nicht schon Anfang des Jahres rauskommen?
Aber bis das irgendwann mal erscheint, kann ich leider nicht warten - Montag Nacht ist Deadline....

Ja...Vererbung ist schon toll (*hust* hab ich da gerade Stack gehört:autsch:)
Ich habs jetzt auch so gemacht, wie Fred angedeutet hat.
Die Superklasse hat ne abstrakte Methode getPosition() und jede Subklasse muss dann zusehen, dass sie das für sich gebacken kriegt...

Vielen Dank jedenfall für eure interessanten Vorschläge :).
 
S

Spacerat

Gast
Also mein Ansatz wäre so etwas:
1. eine Klasse PackageScoped:
[highlight=java]package gameobjects
abstract class GameObject
{
int position;

protected final void setPosition(int position)
{
this.position = position;
}

public final int getPosition()
{
return position;
}
}[/highlight]
1. 2 Klassen Public:
[highlight=java]package gameobjects
public class OffenderObject
extends GameObject
{
}[/highlight]
[highlight=java]package gameobjects
public class DefenderObject
extends GameObject
{
}[/highlight]
Natürlich müssen nun alle weiteren abgeleiteten Klassen von OffenderObject und DefenderObject in anderen Paketen liegen. Das Paket gameobjects sollte "versiegelt" werden.
 
Zuletzt bearbeitet von einem Moderator:
S

Spacerat

Gast
@Noctarius: :oops: Irgendwie sogar schon zwei mal. Aber die Beiträge waren so Kurz (nur unbedeutend Länger als dein voriger), das man sie schnell übersehen kann. Was soll's. Nu' hat der TS wenigstens noch Codebeispiele.
 

Marco13

Top Contributor
Ist zwar nicht die sauberste Lösung, aber immerhin funktioniert sie ;)

Java:
...
      StackTraceElement trace[] = Thread.currentThread().getStackTrace();
...
    }
    catch(Exception ex)
    {
Mit solchen Vorschlägen sollte man vorsichtig sein. Sie könnten dazu führen, dass Leute das tatsächlich in ihre Programme einbauen...
 

thE_29

Top Contributor
Najo, es funktioniert ;)

Desweiteren bringt mir das package genau NIX mehr als protected. Er kann wieder vom gleichen package drauf zugreifen...
Somit eigentlich schlimmer als protected. Bei protected hätten die geerbten Klassen ja was davon (was er ja eigentlich will). Leider können "fremde" Klassen aus dem gleichen package halt auch drauf zugreifen. Nur das ist bei package genauso...
Nur das man es bei package auch noch geschafft hat, wenn man von der Klasse erbt und nicht im gleichen package ist, es nicht geht...

Von daher ist package eher noch die schlechteste Lösung..
 

Hadernlump

Mitglied
Was spricht dagegen alle Methoden die die Position verändern in der Klasse Spielobject zu implementieren? Dazu noch ne abstrakte Methode getGeschwindigkeit(), bzw. alle Faktoren die die Positionsänderungen beieinflussen können, und schon ist man das Problem los.
 
S

SlaterB

Gast
> alle Methoden die die Position verändern in der Klasse Spielobject zu implementieren?

ist doch im ersten Posting bereits so?! abgesehen vom hier irrelevanten Unterschied Attribut/ Methode

> und schon ist man das Problem los

wieso los? dadurch kommen doch die Probleme erst, so kann jede Spielobjekt-Klasse Methoden anderer Spielobjekte aufrufen
 

Hadernlump

Mitglied
Hab mir das in etwa so vorgestellt. Implementiert man das in dieser Form, so ist es nicht mehr nötig das andere Klassen als die Klasse Spielobject die Position verändern. Die abgeleiteten Klassen geben in diesem Fall nur die Geschwindigkeit, mit der sich die Spielobjecte bewegen, vor.

Java:
abstract class Spielobject
{
	private int posX;
	private int posY;
	protected Spielobject(int posX.int posY)
	{
		this.posX = posX;
		this.posY = posY;
	}
	public void move()
	{
		this.posX += getSpeedX();
		this.posY += getSpeedY();
	}
	public abstract int getSpeedX();
	public abstract int getSpeedY();
}
class Gegner extends Spielobject
{
	...
	public int getSpeedX()
	{
		return 10;
	}
	public int getSpeedY()
	{
		return 10;
	}
}

> und schon ist man das Problem los

wieso los? dadurch kommen doch die Probleme erst, so kann jede Spielobjekt-Klasse Methoden anderer Spielobjekte aufrufen

Versteh ich das jetzt falsch oder geht es nicht eher darum das jede abgeleitete Klasse die Position ändern kann und dies nicht erwünscht ist? Um die Methoden anderer Spielobjecte aufzurufen benötigt man ja ersteinmal eine instanz von diesen.
 

thE_29

Top Contributor
Nö, ihr versteht das falsch!
Er will das Unterobjekte == abgeleitete (hoffentlich meinte er das so) die Position verändern können sollen, aber sonst niemand!
 
S

SlaterB

Gast
> Um die Methoden anderer Spielobjecte aufzurufen benötigt man ja ersteinmal eine instanz von diesen.

schau dir die ursprünglichen Beispiele an,
mit deinem Code kann man immer noch kugel.move() aufrufen, auch wenn man selber eine Spielfigur ist und gar nicht die Kugel
 

Hadernlump

Mitglied
Nö, ihr versteht das falsch!
Er will das Unterobjekte == abgeleitete (hoffentlich meinte er das so) die Position verändern können sollen, aber sonst niemand!

Aso jetzt versteh ich des. Kann mir einer von euch erklären in welchem Fall eine solche Einschrenkung nötig ist. ???:L
Um dadurch das Spielgeschehen zu manipulieren sind Änderungen im Code nötig. Und hab ich den Code, dann ist eh schon egal ob die methode jetzt private oder protected ist. Dann kann ich das nach belieben ändern, also z.b. alles public machen um darauf von überall zugreifen zu können.
 

thE_29

Top Contributor
protected lässt dich auch drauf zugreifen, wenn du im gleichen package bist :) Also nicht nur wenn du davon erbst.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
O Ewiges, dummes "end" Java Basics - Anfänger-Themen 6
K Sichtbarkeit protected: Attribute trotzdem aufrufbar. Java Basics - Anfänger-Themen 4
H Kapselung protected aber in einer Kindklasse nicht zugänglich Java Basics - Anfänger-Themen 5
B Vererbung - Sichtbarkeitsmodifikation - protected Java Basics - Anfänger-Themen 10
S Zugriff auf protected Fields = guter Programmierstil? Java Basics - Anfänger-Themen 11
S protected = nicht protected? Java Basics - Anfänger-Themen 9
Aprendiendo Zwei Fragen und ein geerbtes "protected"-Attribut Java Basics - Anfänger-Themen 2
wilmaed protected class Java Basics - Anfänger-Themen 0
K Vererbung protected NUR für Unterklassen? Java Basics - Anfänger-Themen 17
M Schlüsselworte Ohne Modifizierer gleichbedeutend mit protected? Java Basics - Anfänger-Themen 6
K Compiler-Fehler vererbtes protected Java Basics - Anfänger-Themen 41
K Protected und Private Deklaration Java Basics - Anfänger-Themen 8
B Vererbung Probleme bei Zugriff auf protected-Methoden in einer Unterklasse Java Basics - Anfänger-Themen 27
J protected Methoden Java Basics - Anfänger-Themen 8
W Frage public protected konstruktor Java Basics - Anfänger-Themen 6
B Kapselung Klasse private, Konstruktor protected Java Basics - Anfänger-Themen 10
T Kapselung: public-Methoden in protected-Klassen Java Basics - Anfänger-Themen 3
A protected Java Basics - Anfänger-Themen 18
A Frage zu Protected in SubSubKlasse Java Basics - Anfänger-Themen 4
G Protected Variablen außerhalb der eigenen Klassenhierarchie sichtbar Java Basics - Anfänger-Themen 5
N Wann muss eine Methode - protected sein wann public wann. Java Basics - Anfänger-Themen 5
stekoe2000 protected abstrac class Java Basics - Anfänger-Themen 3
B public und protected Java Basics - Anfänger-Themen 11
S Veränderung von Protected Daten durch Übergabe? Java Basics - Anfänger-Themen 3
G Public ,private,protected Java Basics - Anfänger-Themen 1
M Konstruktor protected machen Java Basics - Anfänger-Themen 7
H protected Java Basics - Anfänger-Themen 2
U public, private, protected und "default access" - Java Basics - Anfänger-Themen 14
V Auf protected ArrayList von anderer Klasse zugreifen Java Basics - Anfänger-Themen 4
J protected und Standard Sichtbarkeit Java Basics - Anfänger-Themen 2
M Jede Variable als private, protected etc. deklarieren? Java Basics - Anfänger-Themen 7
P protected funktioniert nicht? Java Basics - Anfänger-Themen 5

Ähnliche Java Themen

Neue Themen


Oben