2012-07-09 127 views
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构造函数传递给Specator的体育场的参考而不是通过this

+2

我相信纯粹主义者会因为紧密的耦合而对这种技术产生畏缩,但它似乎被广泛使用。 “更好”的方法可能是创建一个体育场实现的接口,它定义了外部实体可以对它做些什么,并接受体育场作为观众类中的接口类型。 – itsme86 2012-07-09 23:26:36

+4

这位投机分子如何影响足球场?在我看来,这是确定这里最佳关系类型的关键。 – 2012-07-09 23:45:17

+0

@Esteban,非常简单的逻辑,将属性设置为值。没有什么重用 – user997112 2012-07-10 00:19:28

回答

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

不幸的是,那么你就必须把所有的“旁观者”类你的其他类,这可能导致一个非常长的文件,从而导致丑陋的代码。

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

+0

嗨,这两件事情是我的问题和我的编辑? – user997112 2012-07-10 00:30:20

+0

对不起,你的权利,这不是很清楚。我试图说:不要使用内部类,然后在内部类中引用外部类。我已经看到过这种情况,我可以想到没有理由不需要这样做。 – 2012-07-10 00:34:54

3

这不是那么“糟糕的oo编程”,因为它很紧密coupled。传递this指针没有任何内在的错误,但它可以非常迅速地变成一团糟。没有更多信息,我们无法多说。

+0

我有点尝试通过指针传递方法(就像在C++中那样),除了我通过Spectator接口使用动态绑定(由体育场调用)来对球场进行操作....我无法想象任何其他方式..... – user997112 2012-07-09 23:26:40

+0

只是想,如果不是通过“这个”,而是通过Spectator构造函数将体育场的参考传递给Specator? – user997112 2012-07-09 23:29:54

+0

@ user997112一个'Spectator'是否经常需要在不同的'Stadium'上作用?如果一个“观众”绑定到一个“体育场”,那将是一个更好的解决方案。 – cklab 2012-07-09 23:32:52

2

我看到没有问题,用这个作为参数。不过,我不喜欢在SoccerStadium课程中硬编码的new Spectator()调用。我相信你应该有一个工厂,它有一个createSpectator方法,可以接收一个参数,指明你打算创建哪种类型的旁观者。

+0

说实话,这只是我快速敲打的东西 - 我可以通过构造函数将观众传入体育场,或者像我的编辑一样,我可以做相反的事情吗? – user997112 2012-07-09 23:31:40

+0

关于我的评论的一点是,您的代码新的Spectator()将球场与特定类型的观众紧密耦合在一起。我在想你可以使用工厂模式。尽管如此,我认为你可能在每个体育场都会有不止一个观众,所以你可以在体育场内有一个List(或另一个容器)和一个可以作为参数接收SpectatorInterface的添加方法。之后,球场可以打电话给doSomething(这个)。 – rlinden 2012-07-10 00:15:29

2

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

我通过让球场成为观众分派事件的订户来解耦关系。

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

...等观众现在有任何的兴趣,但并不需要知道关于它的事情通信的手段。

+0

我的编辑建议呢? – user997112 2012-07-10 00:31:06

+1

请参阅我的关于不同Spectator“容器”的编辑。我倾向于建造东西,所以小零件不依赖于它们的容器。它为我提供了很好的服务。 – spender 2012-07-10 00:32:08

+0

我可能会很麻烦并要求提供一个代码示例(如果要进行少量编辑,请使用我的代码示例)? – user997112 2012-07-10 00:36:04

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

有意义吗?

1

正如马特所说,你所描述的是访客模式。尽管如此,我认为这不是你最好的选择(正如Falmarri说的那样,这种设计往往是紧密结合的,而且你最终会在业务对象中投入大量逻辑,打破SoC,SRP等)。 每个观众对于特定活动的行为都不相同,这并不意味着该逻辑应该被包含(也不会传递)通过观众类。有很多不同的方法来避免这些IF语句。我建议你去像this link这样的建议,它比if语句,访问者模式或所有其他选择更强大,并且在另一个类中实现它非常容易,并且保持所有这些商品OOP原则(其中是否有原因)。