6

好的,假设我有一个类,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怎样?

4

6 回答 6

3

这与其说是“糟糕的 oo 编程”,不如说它是紧密耦合的。传递指针本质上没有错this,但它很快就会变得一团糟。如果没有更多信息,我们真的不能说更多。

于 2012-07-09T23:25:15.817 回答
2

我认为使用 this 作为参数没有问题。尽管如此,我不喜欢new Spectator()在你的SoccerStadium课堂上硬编码的电话。我相信您应该有一个带有createSpectator方法的工厂,该方法可以接收一个参数,指示您打算创建哪种类型的观众。

于 2012-07-09T23:28:01.013 回答
2

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

我将通过让 Stadium 成为 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);
        }
    }
}

...因此,观众现在有一种与任何感兴趣的人交流的方式,但不需要知道任何事情。

于 2012-07-10T00:28:45.587 回答
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();
  }
}

有道理?

于 2012-07-10T01:45:41.160 回答
1

你的实现绝对没问题,我以前见过那种东西。是的,您可以通过将它传递给 Spectator 构造函数来保留 Stadium 引用,这可能比每次需要时都发送引用更干净。

但是,我不太喜欢它;我更喜欢内部类。目前尚不完全清楚您要做什么,但可能会发生这样的事情:

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

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

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

于 2012-07-09T23:55:52.767 回答
1

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

于 2012-07-10T02:46:56.767 回答