这是不好的OO编程?通过方法传递这一点

时间:2012-07-09 23:21:28

标签: java oop design-patterns aggregation

好吧,假设我有一个类,X和X是与其他对象有聚合关系的东西。假装X是一个足球场。

X满是观众。然而,每个观众对特定活动的行为不同。而不是IF语句,我希望不同的行为在观众类中,以便我可以使用动态绑定。

然而,问题在于观众所进行的行为会影响“足球场”课程。所以我想把“这个”从足球场的课程,通过一种方法传递给观察者课程,以便观众课能够为足球场的课程做些什么?

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();
    }
}

我只想这样做,以便我可以使用动态绑定并改变Specator.doSomething()中的行为,这样我可以将许多不同类型的SpectatorSuperClass作为传递给SoccerStadium的属性,然后具有不同的行为。

编辑:如果我通过Spectator构造函数将Stadium的引用传递给Specator,而不是传递this,该怎么办?

6 个答案:

答案 0 :(得分:3)

这不是“糟糕的编程”,因为它紧密coupled。传递this指针并没有什么本质上的错误,但它很快就会变得混乱。如果没有更多的信息,我们真的不能说更多。

答案 1 :(得分:2)

我认为使用它作为参数没有问题。不过,我不喜欢new Spectator()课程中硬编码的SoccerStadium来电。我相信你应该有一个createSpectator方法的工厂,它可以接收一个参数,表明你打算创建哪种类型的观众。

答案 2 :(得分:2)

对我来说,这种双向循环关系是坏消息。如果观众想要去剧院呢?

我通过让体育场成为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);
        }
    }
}

......所以Spectator现在有办法与任何有兴趣的人沟通,但不需要了解它。

答案 3 :(得分:2)

正如人们所说,紧密耦合和你正在做的事情绝对没有错。但是,如果您想要进行一些解耦,请使用经典的访问者模式。

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());
}

如果需要,可以更改访问方法签名以接受某种状态对象。否则你可以简单地在Spectator类上定义相关方法,并让访问者收集改变体育场所需的信息。

例如:

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();
  }
}

有意义吗?

答案 4 :(得分:1)

你的实施绝对没问题,我以前见过这种事。是的,您可以通过Spectator构造函数来保持体育场参考,这可能比每次需要时通过参考发送更清晰。

但是,我不太喜欢它;我更喜欢内部课程。目前还不完全清楚你要做什么,但这样的事情是可能的:

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();
}
}

不幸的是,你必须将你所有的“旁观者”类放在你的另一个类中,这可能会导致一个非常长的文件,因而是丑陋的代码。

但是,我认为你绝对应该避免做这两件事,因为这肯定会使你的代码过于复杂。

答案 5 :(得分:1)

正如马特所说,你所描述的是访客模式。尽管如此,我认为这不是你最好的选择(正如Falmarri所说,那种设计往往是紧密耦合的,你最终会在你的业务对象中加入很多逻辑,打破SoC,{{3}等等。)。 对于特定活动的每个观众的行为不同的事实并不意味着逻辑应该被包括(也不通过)观众类。有许多不同的方法可以避免这些IF语句。我建议你选择类似SRP建议的东西比if语句,访问者模式或所有其他替代方案更强大,并且在另一个类中实现它非常容易,并维护所有这些商品OOP原则(有原因)。