6

わかりました、私がクラスを持っていると仮定します.XとXは他のオブジェクトとの集合関係を持つものです。X をサッカー スタジアムとしましょう。

Xはクラスの観客でいっぱいです。ただし、特定のアクティビティに対する各観客の行動は異なります。IF ステートメントの代わりに、動的バインディングを使用できるように、さまざまな動作をスペクテーター クラス内に配置したいと考えています。

しかし問題は、観客が行う行動が「サッカースタジアム」クラスに影響を与えることです。それで、私は「これ」をサッカー スタジアム クラスからメソッドを介して Spectator クラスに渡し、観客クラスがサッカー スタジアム クラスに対して何かを実行できるようにすることを考えていました。

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()動的バインディングを使用して動作を変更し、SoccerStadium に渡される属性として多くの異なるタイプの SpectatorSuperClass を持ち、異なる動作を実行できるようにするために、これを実行したいだけです。

編集: を渡すのではなく、Spectator コンストラクターを介して、Stadium の参照を Specator に渡すとどうなりthisますか?

4

6 に答える 6

3

これは、密結合であるため、「悪い oo プログラミング」ではありません。ポインターの受け渡しに本質的に問題はありませんthisが、すぐに混乱する可能性があります。これ以上の情報がなければ、これ以上のことは言えません。

于 2012-07-09T23:25:15.817 に答える
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);
        }
    }
}

...これで、スペクテイターは興味のあるものと通信する手段を手に入れましたが、それについて何も知る必要はありません。

于 2012-07-10T00:28:45.587 に答える
2

これをパラメーターとして使用しても問題はありません。それにもかかわらず、あなたのクラスnew Spectator()でハードコーディングされた呼び出しは好きではありません。作成するスペクテーターのタイプを示すパラメーターを受け取ることができるメソッドをSoccerStadium備えた Factory が必要だと思います。createSpectator

于 2012-07-09T23:28:01.013 に答える
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());
}

必要に応じて、visit メソッドのシグネチャを変更して、ある種の状態オブジェクトも受け入れることができます。それ以外の場合は、単に 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();
}
}

残念ながら、その場合、他のクラス内にすべての「スペクテイター」クラスを含める必要があります。これにより、1つの非常に長いファイルが作成され、コードが醜くなる可能性があります。

ただし、コードが非常に複雑になるため、両方を行うことは絶対に避けてください。

于 2012-07-09T23:55:52.767 に答える
1

マットが言ったように、あなたが説明しているのは訪問者パターンです。それにもかかわらず、それが最善の選択肢ではないと思います(Falmarriが言ったように、そのような設計は密結合になる傾向があり、ビジネスオブジェクトに多くのロジックを入れて、SoCSRPなどを壊してしまいます..)。特定のアクティビティに対する各スペクテーターの動作が異なるという事実は、ロジックがスペクテーター クラスに含まれる (パスされる) 必要があるという意味ではありません。これらの IF ステートメントを回避するには、さまざまな方法があります。このリンクのようなものを使用することをお勧めしますif ステートメント、ビジター パターン、または他のすべての代替手段よりもはるかに強力なものを提案し、それを別のクラスに実装して、すべての適切な OOP 原則 (理由があります) を維持するのは非常に簡単です。

于 2012-07-10T02:46:56.767 に答える