1

数年間 HTML/CSS コーディングを行った後、Java の学習を始めたばかりなので、ここで古い質問や愚かな質問をしていないことを願っていますが、この問題を説明する助けをいただければ幸いです。

私は現在、スタンフォード CS106A オンライン教材に取り組んでおり、第 6 週、課題 2、質問 3 (http://see.stanford.edu/materials/icspmcs106a/13-assignment-2-simple-java.pdf) に到達しました。 )。

ご覧のとおり、グラフィックス階層を作成するには、画面上にさまざまなオブジェクトを配置する必要があります。私の計画は、中心座標を使用して、画面上のすべてのオブジェクトを相対的に配置することでした。しかし、答えが見つからないように見える問題にぶつかりました。このコースでは、メソッド分解が各メソッドで 1 つの問題を処理できるようにする方法について説明します (単一責任の原則だと思います)。そのため、コードの最初の部分を次のように記述しました。

//Import any libraries
import acm.program.*;
import acm.graphics.*;

    public class GraphicsHierarchy extends GraphicsProgram {

//Define constants
static final int BOX_WIDTH = 200;
static final int BOX_HEIGHT = 75;



public void run() {
    placeGRect();
}   

//Find centre x & y
double centre_x = getWidth() / 2; //check this
double centre_y = getHeight() * 0.5;//and this

//placeGRect method
public void placeGRect() {
    for (int count = 0; count < 4; count++) {
        GRect box = new GRect (BOX_WIDTH, BOX_HEIGHT);
        add(box);
        switch (count) {
        case 0:
            box.setLocation(centre_x, 75);
            break;
        case 1:
            box.setLocation((centre_x * 0.5), 250);
            break;
        case 2:
            box.setLocation(centre_x, 250);
            break;
        case 3:
            box.setLocation((centre_x * 1.5), 250);
            break;
        }
    }
}
}

ただし、 center_x と center_y がゼロの値を生成するため、これは機能しません。プログラムを ConsoleProgram に変更し、 getWidth と getHeight の行を run() メソッド内に配置して (そしてそれらの値を画面に表示して)、必要な値を生成しましたが、それらを GRect メソッドに渡しませんでした (そのため、それでもうまくいきませんでした)。ただし、run() からリストされた getWidth/getHeight 行がある場合、それらは相対位置の値を生成しません。

私の質問は、各メソッドが 1 つのタスクを処理する必要があり、(可能な限り) メソッドが run() メソッドから定義されている必要があるということです。 run() メソッド内のコードの大きなブロック。私が理解しているのは悪い習慣です。

私はこれを解決するためのコードを求めているわけではありません。将来的に効果的なコードを書くことができるように、この原則を理解する必要があります。オウムのようにコードをコピーするよりも、理解することを好みます。

助けてくれてありがとう。

4

4 に答える 4

1

あなたの特定の例では:

centre_xandcentre_yをインスタンス変数として宣言しました。プログラムが最初GraphicsHierarchyにオブジェクト作成のインスタンスを作成するときは、次のようになります。

  1. ClassLoader はクラスをロードします... 静的変数 ( BOX_WIDTHBOX_HEIGHT) には指定された値が割り当てられます。

  2. インスタンス用のスペースがヒープに割り当てられますGraphicsHierarchy(インスタンス変数を保持するのに十分なスペース - doubleforcentre_xおよびdoublefor centre_y- 基本クラスのインスタンス変数用のスペースを含む)

  3. インスタンス変数はデフォルト値に設定されています: centre_x= 0, centre_y= 0

  4. デフォルトのGraphicsHierarchyコンストラクターが呼び出されます (これは、基本クラスのコンストラクターを呼び出す以外には何もしません - GraphicsProgram)。

  5. 基本クラスはステップ 1 ~ 4 を通過し、実行が終了すると に戻りGraphicsHiearchy、残りのコンストラクター ステートメントを実行する前に明示的なインスタンス変数初期化子を評価します (既定のコンストラクターの場合は何もありません)。

(このプロセスに関する追加参照http://java.dzone.com/articles/java-object-initialization )

以上のことをすべて述べた後、クラスGraphicsHierarchyがステップ 5 に到達して および に値を代入しようとするcentre_xと、およびが依存するcentre_yサブシステムの準備ができていないように見えます (つまり、ウィンドウまたはキャンバスがまだ作成されていないため、メソッドは戻ります0)。しかし、割り当てを run および/の戻り値内に移動すると、run を呼び出しているメソッドが最初に必要なウィンドウ作成手順を実行したことを意味します。getWidthgetHeightgetWidthgetHeight

Etienne de Martel の提案は結構です。必要になる直前まで、中心値の割り当てを遅らせます。必要に応じて、init メソッドを作成し、割り当てを init メソッド内に移動してから、実行の最初のステップとして init を呼び出すことができます。

private void init() {
    centre_x = getWidth / 2;
    centre_y = getHeight * 0.5;
}

public void run() {
    init();
    placeGRect();
}

これは Martel の提案とほぼ同じですが、後で実行する必要がある他の初期化コードが見つかった場合は、同じ場所にスローできます。

placeGRect柔軟なコードを作成する場合は、名前を変更してplaceGRectsポイントの配列 (または必要に応じてコレクション) を渡すことを考えるかもしれません。placeGRects(Point[] points)

(Java.awt.Point を使用するか、独自の Point クラスを定義できます)

このようにして、placeGRects メソッドが単純化されます。レンダリングするボックスの数を決定しなくなりました (渡される配列が決定します)。また、これらの新しいボックスが配置されている場所も特定しません (ここでも Point オブジェクトの配列が特定します)。配列のサイズをループし、新しいボックスを作成して追加し、場所を設定するだけです。

private Point[] boxPoints;

public void run() {
    init();
    placeGRects(boxPoints);
}

public void placeGRects(Point[] points) {
    for(int i=0;i<points.length;i++) {
        GRect b = new GRect(BOX_WIDTH,BOX_HEIGHT); 
        add(b);
        b.setLocation(points[i].x,points[i].y);
    }
}

そして、Point 配列の初期化を新しい init() メソッド内に置くことができます。

private void init() {
    centre_x = getWidth / 2;
    centre_y = getHeight * 0.5;
    boxPoints = {new Point(centre_x, 75),new Point(centre_x * 0.5, 250)}; 
}

コードを理解しやすくし、必要に応じて変更できるようにします。

于 2011-05-05T16:54:23.687 に答える
0

おそらく私はあなたの質問を理解していませんが、それらをパラメーターとして渡してみませんか?

protected void placeGRect(double centre_x, double centre_y) {
    // ...
}

placeGRect次に、次のように呼び出すことができます。

public void run() {
    placeGRect(getWidth() / 2, getHeight() * 0.5);
}
于 2011-05-05T14:25:46.807 に答える
0

とてもいい質問です!メソッドをどのように構成するかは、厳密なガイドラインではなく直感の問題です。

確かに、メソッドは 1 つのことだけを行うことに集中する必要があります。まず、短いメソッド (ワンライナーでも!) を使用すると、コードが理解しやすくなります。非常に大まかな例として、次のことを考えてください。

if (DateUtils.before(ticket.getExpirationDate(), new Date())) {
   accept(ticket);
}

そして、これ

if (isNotExpired(ticket)) {
   accept(ticket);
}

...

private boolean isNotExpired(Ticket t) {
   return DateUtils.before(t.getExpirationDate(), now());
}

private Date now() {
  return (new Date());
}

1 行のメソッドisNotExpired()now()の導入によって、コードの機能に対する理解が大幅に向上したことに注意してください。

別の例を次に示します。今回は、オブジェクトの構築に関係しています。

Loan l1 = new Loan(15000, 36, f7.2, 2.5);
Loan l2 = new Loan(15000, 36, f7.2);

対。

Loan l1 = Loan.newSubsidizedLoan(15000, 36, f7.2, 2.5);
Loan l2 = Loan.newNormalLoan(15000, 36, f7.2);

この例では、コンストラクターを 2 つの異なるメソッドでラップすると、コードのドキュメントが大幅に改善されることに注意してください (コメントを記述する必要さえありません)。

コーディング スタイルの一般的なトピックに興味がある場合は、この本を読む必要があります。

乾杯

L.

于 2011-05-05T15:19:01.030 に答える
-1

コードにgetWidth()メソッドとgetHeight()メソッドが含まれていないようです。また、次のコードは配置として完全に間違っているため、コンストラクターに配置する必要があります。

double centre_x = getWidth() / 2; //check this
double centre_y = getHeight() * 0.5;//and this

になるはずです

private double centre_x;
private double centre_y; 
GraphicsHierarchy(){
    centre_x = GraphicsHierarchy.BOX_WIDTH / 2;
    centre_y = GraphicsHierarchy.BOX_HEIGHT * 0.5;
}

このコードは少なくともコンパイルされますが、以下で説明する解決策を検討してください。これはさらに優れています。

BOX_WIDTHとBOX_HEIGHTを静的変数として定義したことを考えると、center_xとcenter_yはいつでも見つけることができます。したがって、BOX_WIDTHとBOX_HEIGHTを定義する必要はありません。

次のようにクラスを定義できます。

//Import any libraries
import acm.program.*;
import acm.graphics.*;

public class GraphicsHierarchy extends GraphicsProgram {
public void run() {
    placeGRect();
}   
//Define constants
public static final double CENTRE_X= 100.00; 
public static final double CENTRE_Y = 37.50;
//placeGRect method
public void placeGRect() {
    for (int count = 0; count < 4; count++) {
        GRect box = new GRect (200, 75);
        add(box);
        switch (count) {
        case 0:
            box.setLocation(GraphicsHierarchy.CENTRE_X, 75);
            break;
        case 1:
            box.setLocation((GraphicsHierarchy.CENTRE_X * 0.5), 250);
            break;
        case 2:
            box.setLocation(GraphicsHierarchy.CENTRE_X, 250);
            break;
        case 3:
            box.setLocation((GraphicsHierarchy.CENTRE_X * 1.5), 250);
            break;
        }
    }
}
}

私の意見では、すべての計算を排除してそのようなものを置き換えることで、さらに先に進むことができます

GraphicsHierarchy.CENTRE_X * 1.5 

150

さあ、あなたの仮想マシンでそれを簡単にしてください!クラスは静的な情報を大量に使用するため、それほど多くの計算を行う必要はありません。ただし、BOX_WIDTHとBOX_HEIGHTを定数として使用することは、内部で1つの場所でのみ使用されるため、まったく役に立ちません。BOX_WIDTHとBOX_HEIGHTからcenter_xとcenter_yを計算することも役に立ちません。これらは最終的なものであるため、自分で簡単に計算を実行し、不要な変数の作成を減らすことができます。

さらに、center_y値はどこにも使用しないため、破棄する必要があります。

さらに役立つアドバイスを追加するには、NetBeans、Eclipse、IntellIJIDEAなどの適切なIDEにコード補完と構文の強調表示が必要であり、より優れた(またはより知識が豊富でさらに優れた)プログラマーになるのに非常に役立ちます。

于 2011-05-05T15:48:01.103 に答える