程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java面向對象編程實例詳解

Java面向對象編程實例詳解

編輯:關於JAVA

Java是一種面向對象的語言,是實現面向對象編程的強大工具。但如何在編程中實際運用並發揮其最大效能呢?本文通過一個實際Java程序的開發過程,詳細說明了如何使用面向對象實現Java編程。

我們要實現的Java應用程序是:當用戶輸入一個球體的半徑,程序將顯示該球體的體積與表面積。在您閱讀下文以前,請您自己思考一分鐘,您將如何設計該Java應用程序。

一、普通實現方法

我相信大多數程序員要實現上述功能的程序,非常迅速地、自信地將采用下面的實現代碼:

class Sphere
{
public static void main(String[] args)
{
EasyReader console = new EasyReader();
System.out.print("Enter the radius: ");
double radius = console.readDouble();
System.out.println("Radius = " + radius);
double volume = 4.0 / 3.0 * Math.PI * radius * radius * radius;
System.out.println("Volume = " + volume);
double surfArea = 4.0 * Math.PI * radius * radius;
System.out.println("Surface area = " + surfArea);
}
}

EasyReader類代碼如下:

import java.io.*;
public class EasyReader
{
protected String myFileName;
protected BufferedReader myInFile;
protected int myErrorFlags = 0;
protected static final int OPENERROR = 0x0001;
protected static final int CLOSEERROR = 0x0002;
protected static final int READERROR = 0x0004;
protected static final int EOF = 0x0100;
/**
* Constructor. Prepares console (System.in) for reading
*/
public EasyReader()
{
myFileName = null;
myErrorFlags = 0;
myInFile = new BufferedReader(
new InputStreamReader(System.in), 128);
}
/**
* Constructor. opens a file for reading
* @param fileName the name or pathname of the file
*/
public EasyReader(String fileName)
{
myFileName = fileName;
myErrorFlags = 0;
try
{
myInFile = new BufferedReader(new FileReader(fileName), 1024);
}
catch (FileNotFoundException e)
{
myErrorFlags |= OPENERROR;
myFileName = null;
}
}
/**
* Closes the file
*/
public void close()
{
if (myFileName == null)
return;
try
{
myInFile.close();
}
catch (IOException e)
{
System.err.println("Error closing " + myFileName + "\n");
myErrorFlags |= CLOSEERROR;
}
}
/**
* Checks the status of the file
* @return true if en error occurred opening or reading the file,
* false otherwise
*/
public boolean bad()
{
return myErrorFlags != 0;
}
/**
* Checks the EOF status of the file
* @return true if EOF was encountered in the previous read
* operation, false otherwise
*/
public boolean eof()
{
return (myErrorFlags & EOF) != 0;
}
private boolean ready() throws IOException
{
return myFileName == null || myInFile.ready();
}
/**
* Reads the next character from a file (any character including
* a space or a newline character).
* @return character read or <code>null</code> character
* (Unicode 0) if trying to read beyond the EOF
*/
public char readChar()
{
char ch = '\u0000';
try
{
if (ready())
{
ch = (char)myInFile.read();
}
}
catch (IOException e)
{
if (myFileName != null)
System.err.println("Error reading " + myFileName + "\n");
myErrorFlags |= READERROR;
}
if (ch == '\u0000')
myErrorFlags |= EOF;
return ch;
}
/**
* Reads from the current position in the file up to and including
* the next newline character. The newline character is thrown away
* @return the read string (excluding the newline character) or
* null if trying to read beyond the EOF
*/
public String readLine()
{
String s = null;
try
{
s = myInFile.readLine();
}
catch (IOException e)
{
if (myFileName != null)
System.err.println("Error reading " + myFileName + "\n");
myErrorFlags |= READERROR;
}
if (s == null)
myErrorFlags |= EOF;
return s;
}
/**
* Skips whitespace and reads the next word (a string of consecutive
* non-whitespace characters (up to but excluding the next space,
* newline, etc.)
* @return the read string or null if trying to read beyond the EOF
*/
public String readWord()
{
StringBuffer buffer = new StringBuffer(128);
char ch = ' ';
int count = 0;
String s = null;
try
{
while (ready() && Character.isWhitespace(ch))
ch = (char)myInFile.read();
while (ready() && !Character.isWhitespace(ch))
{
count++;
buffer.append(ch);
myInFile.mark(1);
ch = (char)myInFile.read();
};
if (count > 0)
{
myInFile.reset();
s = buffer.toString();
}
else
{
myErrorFlags |= EOF;
}
}
catch (IOException e)
{
if (myFileName != null)
System.err.println("Error reading " + myFileName + "\n");
myErrorFlags |= READERROR;
}
return s;
}
/**
* Reads the next integer (without validating its format)
* @return the integer read or 0 if trying to read beyond the EOF
*/
public int readInt()
{
String s = readWord();
if (s != null)
return Integer.parseInt(s);
else
return 0;
}
/**
* Reads the next double (without validating its format)
* @return the number read or 0 if trying to read beyond the EOF
*/
public double readDouble()
{
String s = readWord();
if (s != null)
return Double.parseDouble(s);
// in Java 1, use: return Double.valueOf(s).doubleValue();
else
return 0.0;
}
}

以下是程序的輸出結果畫面。

在上述程序中,實現了球體表面積和體積的算法,並通過EasyReader類輕松實現了控制台的輸入,但是該程序只是完成了程序所要求的功能,並計算出了結果。該程序不是一個好的設計程序,它既沒采用結構化編程,也沒有發揮Java語言的強大效能,更不是面向對象編程。

實際上,從程序設計的角度來看,以上程序是一個非常糟糕的設計程序。首先,用戶界面與計算公式混合在一起。請記住:對於任何編程語言,用戶界面必須與計算或處理過程分離開來。另外,輸出的結果太難看,數值包括太多的小數。

二、結構化編程方法

在以下的程序代碼中,我們添加了2個方法,分別實現球體表面積與體積的計算,並通過相應的類控制數值的輸出格式。

import java.text.DecimalFormat;
class Sphere
{
// Computes the volume of a sphere with radius r.
private static double volume(double r)
{
return 4.0 / 3.0 * Math.PI * r * r * r;
}
// Computes the surface area of a sphere with radius r.
private static double surfaceArea(double r)
{
return 4.0 * Math.PI * r * r;
}
public static void main(String[] args)
{
EasyReader console = new EasyReader();
System.out.print("Enter the radius: ");
double radius = console.readDouble();
DecimalFormat f3 = new DecimalFormat("0.000");
System.out.println(); // displays a blank line
System.out.println("Radius = " + f3.format(radius));
System.out.println("Volume = " + f3.format(volume(radius)));
System.out.println("Surface area = " + f3.format(surfaceArea(radius)));
System.out.println();
}
}

以下是輸出結果。

上述經過修改後的程序,其輸出結果看起來漂亮多了,但它仍只是一個勉強可以通過的設計程序。該程序采用了結構化編程的風格,並不是面向對象編程。首先,計算過程仍與用戶界面實現在同一個類中。另外,對於不同的用戶界面,不能體現出面向對象編程的好處,即不能重用這些計算過程。

三、面向對象編程方法

要實現上述程序的面向對象編程,我們必須注意:Java應用程序中的每一個類或對象,必須單獨實現自己的任務。具體來說,在本程序中,一個類定義球體,即模型或數據表示(Model),另一個類就是實現用戶界面(UI)。

另外更重要的,也是中國程序員常常忽視的,就是要考慮到團體的開發與管理,實現面向對象編程,就是讓開發組中的每個程序員能獨立開發不同的類,非常迅速地提高開發效率。

因此,對於本程序來說,面向對象編程的設計方法就是將Model與UI分別是實現在不同的類中。其示意圖如下:

以下分別是該程序的UML類圖設計與程序代碼。有關UML類圖的設計與應用,請查閱作者的另文(《利用UML類圖設計Java應用程序詳解一、二》)

Sphere的類圖設計為:

其代碼為:

class Sphere
{
private double myRadius;
private double myCenterX;
private double myCenterY;
// Constructors:
public Sphere (double x, double y, double r)
{
myCenterX = x;
myCenterY = y;
myRadius = r;
}
// etc...
// Accessors and modifiers:
public double getRadius()
{
return myRadius;
}
public void setRadius(double r)
{
myRadius = r;
}
// etc...
// Other public methods:
public double volume()
{
return 4.0 / 3.0 * Math.PI * myRadius * myRadius * myRadius;
}
public double surfaceArea()
{
return 4.0 * Math.PI * myRadius * myRadius;
}
public String toString()
{
return "Sphere [Center = (" + myCenterX + ", " + myCenterY + ") Radius = " + myRadius
+ "]";
}
}

TestSphere的類圖為:

其實現代碼為:

import java.text.DecimalFormat;
class TestSphere
{
public static void main(String[] args)
{
EasyReader console = new EasyReader();
System.out.print("Enter the radius: ");
double radius = console.readDouble();
DecimalFormat f3 = new DecimalFormat("0.000");
Sphere balloon = new Sphere(0, 0, radius);
System.out.println();
System.out.println(balloon);
System.out.println("Volume = " + f3.format(balloon.volume()));
System.out.println("Surface area = " + f3.format(balloon.surfaceArea()));
System.out.println();
}
}

該程序的各類之間的相互關系可以表示為:

該程序的UML序列圖可以表示如下。有關UML序列圖的設計與應用,請查閱作者的另文(《利用UML序列圖設計Java應用程序詳解》)

以下是程序的輸出結果。

四、設計圖形用戶界面(GUI)

以上程序利用面向對象編程的設計方法,較好地實現了Java應用程序。但美中不足的是,沒有圖形用戶界面供用戶使用。

如果我們要增加設計圖形用戶界面,我們就可以將類Sphere交給一個程序員去實現,將用戶界面SphereWindow交給另外一個程序員去開發,這就是面向對象編程的好處,可以進行團隊開發,而不是作坊式的傳統的程序開發方式。

以下是用戶界面SphereWindow的實現代碼:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.text.DecimalFormat;
public class SphereWindow extends JFrame
implements ActionListener
{
private JTextField radiusIn, volumeOut, surfAreaOut;
private Sphere balloon;
private DecimalFormat f3 = new DecimalFormat("0.000");
public SphereWindow()
{
super("Spheres: volume and surface area");
JPanel view = new JPanel();
view.setLayout(new GridLayout(6, 2, 10, 10));
view.setBorder(new EmptyBorder(10, 10, 10, 10));
view.add(new JLabel("Radius = ", SwingConstants.RIGHT));
radiusIn = new JTextField(8);
radiusIn.setBackground(Color.yellow);
radiusIn.addActionListener(this);
view.add(radiusIn);
view.add(new JLabel("Volume = ", SwingConstants.RIGHT));
volumeOut = new JTextField(8);
volumeOut.setEditable(false);
volumeOut.setBackground(Color.white);
view.add(volumeOut);
view.add(new JLabel("Surface area = ", SwingConstants.RIGHT));
surfAreaOut = new JTextField(8);
surfAreaOut.setEditable(false);
surfAreaOut.setBackground(Color.white);
view.add(surfAreaOut);
view.add (new JPanel()); // reserved
Container c = getContentPane();
c.add(view, BorderLayout.CENTER);
balloon = new Sphere(0,0,100);
}
public void actionPerformed(ActionEvent e)
// Called automatically when the user
// strikes Enter on the input field
{
String s = radiusIn.getText();
double r = Double.parseDouble(s);
balloon.setRadius(r);
radiusIn.setText(" " + f3.format(r));
volumeOut.setText(" " + f3.format(balloon.volume()));
surfAreaOut.setText(" " + f3.format(balloon.surfaceArea()));
}
public static void main(String[] args)
{
SphereWindow w = new SphereWindow();
w.setSize(300, 250);
w.addWindowListener(new ExitButtonListener());
w.show();
}
}
ExitButtonListener類的代碼為:
import java.awt.event.*;
public class ExitButtonListener extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}

通過實現上述程序,利用面向對象編程的設計方法,我們將Model(模型,這裡是Sphere)與view(視圖,這裡是SphereWindow)分離開來。並較好地實現了類的封裝,類的重用(Sphere)。便於團隊開發,迅速提高開發效率。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved