2012-07-09 9 views
6

Ok, supongamos que tengo una clase, X y X es algo que tiene una relación total con otros objetos. Vamos a pretender que X es un estadio de fútbol.¿Es esta una mala programación de OO? Pasando esto a través de los métodos

X está lleno de espectadores de clase. Sin embargo, el comportamiento de cada espectador para una actividad particular difiere. En lugar de las declaraciones IF, quiero que el comportamiento diferente esté dentro de la clase del espectador, de modo que pueda usar el enlace dinámico.

Sin embargo, el problema es que el comportamiento del espectador afecta la clase de "estadio de fútbol". Entonces, ¿estaba pensando en pasar "esto" de la clase del estadio de fútbol, ​​a través de un método, a la clase Spectator, para que la clase de espectadores pueda hacer algo en la clase de Soccer Stadium?

public class SoccerStadium{ 
    SpecatorInterface s = new Spectator(); 

    public void SpectatorBehaviour(){ 
     s.doSomething(this); 
    } 

    public void doSomethingthingBySpecator(){ 
    } 
} 

public class Spectator implements SpecatorInterface{ 
    public void doSomething(SoccerStadium s){ 
     s.doSomethingthingBySpecator(); 
    } 
} 

Yo sólo quiero hacer esto para que pueda utilizar el enlace dinámico y alterar el comportamiento en Specator.doSomething() para que pueda tener un montón de diferentes tipos de SpectatorSuperClass como un atributo pasado al SoccerStadium y luego tener el comportamiento diferente.

EDITAR: ¿Qué sucede si paso la referencia del estadio al Specator a través del constructor de Spectator, en lugar de pasar this?

+2

Creo que los puristas se avergonzarán con esa técnica debido al acoplamiento apretado, pero parece ser ampliamente utilizado. Un enfoque "mejor" podría ser crear una interfaz que implemente el estadio que defina lo que una entidad externa puede hacerle y aceptar el estadio como ese tipo de interfaz en su clase de espectador. – itsme86

+4

¿Cómo afecta exactamente el specator al estadio de fútbol? Me parece que es un punto clave para determinar el mejor tipo de relación aquí. –

+0

@Esteban, lógica muy simple, establecimiento de atributos a valores. Nada pesado – user997112

Respuesta

1

Su implementación es absolutamente buena, he visto ese tipo de cosas antes. Sí, puedes conservar la referencia del estadio pasándola por el constructor de Spectator, que probablemente sería más limpio que enviar la referencia cada vez que la necesites.

Sin embargo, no me gusta mucho; Prefiero clases internas. No es del todo claro lo que estamos tratando de hacer, pero algo como esto es posible:

public class Outer { 

private int someVariable=0; 

public void someMethod(){ 
    ExtendsInner ei = new ExtendsInner(); 
    ei.innerMethod(); 
    System.out.println(someVariable); 
} 

private void anotherMethod(){ 
    someVariable++; 
} 

public abstract class Inner { 
    public abstract void innerMethod(); 
} 

public class ExtendsInner extends Inner{ 
    public void innerMethod(){ 
     anotherMethod(); 
     someVariable++; 
    } 
} 

public static void main(String[] args){ 
    Outer o = new Outer(); 
    o.someMethod(); 
} 
} 

Desafortunadamente, usted entonces tiene que tener todas sus clases "espectador" dentro su otra clase, lo que podría conducir a un archivo realmente largo, y por lo tanto, código feo.

Sin embargo, creo que definitivamente deberías evitar hacer ambas cosas, ya que definitivamente hará que tu código sea demasiado complicado.

+0

hola, ambas cosas son mi pregunta y mi edición? – user997112

+0

lo siento, tiene razón, no está muy claro.Estaba tratando de decir: no use clases internas y luego ponga una referencia a la clase externa en la clase interna. He visto esto hecho antes, y no puedo pensar en ninguna razón por la que alguna vez necesites hacer esto. –

3

Esto no es tanto "mala programación oo" como está estrechamente coupled. No hay nada intrínsecamente incorrecto al pasar alrededor de this punteros, pero puede convertirse en un desastre muy rápidamente. No podemos decir más sin más información.

+0

Estoy tratando de pasar un método por puntero (como lo haría en C++), excepto que estoy usando el enlace dinámico a través de la interfaz del espectador, que es llamado por el estadio, para actuar sobre el estadio ... No puedo pensar de cualquier otra manera ..... – user997112

+0

¿Qué pasa si en lugar de pasar "esto", pasé la referencia del estadio al Specator a través del constructor de Spectator? – user997112

+0

@ user997112 ¿A menudo un 'Spectator' debe actuar en diferentes' Stadium's? Si un 'Espectador' está vinculado a un solo' Estadio', esa sería una mejor solución. – cklab

2

No veo ningún problema con el uso de esto como parámetro. Sin embargo, no me gusta la llamada new Spectator() que estaba codificada en su clase SoccerStadium. Creo que deberías tener una fábrica con un método createSpectator que podría recibir un parámetro que indique qué tipo de espectador pretendes crear.

+0

Honestamente, eso fue algo que rápidamente destruí: podía pasar al espectador al estadio a través del constructor o, como mi edición, Podría hacer el reverso? – user997112

+0

El punto acerca de mi comentario es que su código nuevo Spectator() une estrechamente el Stadium con un tipo específico de espectador. Estaba pensando que podrías usar el patrón Factory. Sin embargo, creo que probablemente tengas más de un espectador en cada estadio, por lo que podrías tener en Stadium a List (u otro contenedor) y un método add que recibiría como parámetro SpectatorInterface. Luego, el estadio podría llamar a algo (esto). – rlinden

2

Para mí, este tipo de relación circular bidireccional es una mala noticia. ¿Qué pasa si los espectadores quieren ir al teatro en su lugar?

Disociaría la relación al hacer que el estadio sea suscriptor de eventos enviados por Spectator.

public class SoccerStadium 
{ 
    ISpectator s = new Spectator(); 
    public SoccerStadium() 
    { 
     s.DidSomething+=DoSomethingthingBySpecator; 
    } 
    public void SpectatorBehaviour() 
    { 
     s.DoSomething(); 
    } 
    public void DoSomethingthingBySpecator(object sender,EventArgs e) 
    { 
     Console.WriteLine("spectator did something"); 
    } 
} 
public interface ISpectator 
{ 
    event EventHandler DidSomething; 
    void DoSomething(); 
} 
public class Spectator:ISpectator 
{ 
    public event EventHandler DidSomething; 
    public void DoSomething() 
    { 
     var ev=DidSomething; 
     if(ev!=null) 
     { 
      ev(this,EventArgs.Empty); 
     } 
    } 
} 

... y por lo que el espectador tiene ahora un medio de comunicación a todo lo que le interesa, pero no necesita saber nada al respecto.

+0

¿qué pasa con mi propuesta de EDITAR? – user997112

+1

Ver mi edición sobre diferentes 'contenedores' de espectadores. Tiendo a construir cosas para que las piezas pequeñas no dependan de sus contenedores. Me sirve muy bien. – spender

+0

¿Podría ser problemático y pedir un ejemplo de código (usando el mío si hay pocas ediciones por hacer)? – user997112

2

Como han dicho las personas, no hay absolutamente nada de malo en un acoplamiento hermético y hermético y en lo que está haciendo. Sin embargo, si desea un poco de desacoplamiento, use el patrón de visitante clásico.

public interface SpectatorVisitor { 
    ... 
    void visit(Spectator spectator); 
} 

public class Spectator { 
    ... 
    public void accept(SpectatorVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

public class Stadium { 

    ... 
    spectator.accept(new StadiumSpectatorVisitor()); 
} 

La firma del método de visita se puede modificar para aceptar algún tipo de objeto de estado también si es necesario. De lo contrario, simplemente podría definir los métodos relevantes en la clase Spectator y hacer que el visitante recopile la información necesaria para alterar el estadio.

Por ejemplo:

public class Spectator { 
    private Team supports; 

    public Team getSupports() { 
     return supports; 
    } 

    public void accept(SpectatorVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

public class SupportedTeamVisitor { 
    private Map<Team, AtomicLong> supportCount = new HashMap<Team, AtomicLong>(); 

    public void visit(Spectator spectator) { 
    Team supports = spectator.getSupports(); 
    if (! supportCount.contains(supports)) { 
     supportCount.put(team, new AtomicLong(0)); 
    } 
    supports.get(team).incrementAndGet(); 
    } 

    public Map<Team, AtomicLong> getSupportCount() { 
    return supportCount; 
    } 
} 


public class Stadium { 

    public long getSupportCount(Team team) { 
    SupportTeamVisitor visitor = new SupportedTeamVisitor(); 
    for (Spectator spectator : spectators) { 
     spectator.accept(visitor); 
    } 
    AtomicLong count = visitor.getSupportCount().get(team); 
    return (count == null) ? 0 : count.get(); 
    } 
} 

sentido?

1

Como dijo Matt, lo que está describiendo es el patrón de visitante. Sin embargo, no creo que esa sea tu mejor alternativa (como dijo Falmarri, ese tipo de diseño tiende a estar estrechamente vinculado, y terminas poniendo mucha lógica en tu objeto comercial, rompiendo SoC, SRP, etc.). El hecho de que el comportamiento de cada espectador para una actividad particular difiera, no significa que la lógica deba incluirse (ni pasar) a través de la clase del espectador. Hay muchas formas diferentes de evitar esas declaraciones IF. Te sugiero que veas algo como this link sugiriendo que es mucho más poderoso que las declaraciones if, patrón de visitante o todas las demás alternativas, y es realmente fácil implementarlo en otra clase, y mantener todos esos principios de POO de bienes (que están ahí por una razón).

Cuestiones relacionadas