【连载】Java学习系列(008)——深入面向对象-2
2015-05-13 22:14
246 查看
【连载】Java学习系列(008)——深入面向对象-2
接口:在Java中,接口是实现可插入特性的保证。定义接口的关键字是interface,实现接口的关键字是implements,一个类可以实现多个接口,接口之间的继承支持多重继承。接口和抽象类的异同
相同点:都不能被直接实例化,都可以通过继承实现其抽象方法。
不同点:
1,抽象类里可以有构造方法,而接口内不能有构造方法。
2,抽象类中可以有普通成员变量,而接口中不能有普通成员变量。
3,抽象类中可以包含非抽象的普通方法,而接口中所有的方法必须是抽象的,不能有非抽象的普通方法。
4,抽象类中的抽象方法的访问类型可以是public ,protected和默认类型,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5,抽象类中可以包含静态方法,接口内不能包含静态方法。
6,抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static类型,并且默认为public static类型。
7,一个类可以实现多个接口,但只能继承一个抽象类。
都是面向抽象编程的技术基础,实现了诸多的设计模式。
类/类和类/接口之间的关系
IS-A关系:继承/实现
HAS-A关系:关联/聚合(聚集)/合成
USE-A关系:依赖
UML:统一建模语言(标准的图形化符号)
类图:描述类以及类和类之间关系的图形符号。
用例图:捕获需求。
时序图:描述对象交互关系。
面向对象的设计原则
单一职责原则(SRP):类的设计要做到高内聚,一个类只承担单一的职责(不做不该它做的事情)。
开闭原则(OCP):软件系统应该接受扩展(对扩展开放),不接受修改(对修改关闭)。要符合开闭原则:抽象是关键,封装可变性。
依赖倒转原则(DIP):面向接口编程。声明变量的引用类型,声明方法的参数类型,声明方法的返回类型时,尽可能使用抽象类型而不是具体类型。
里氏替换原则(LSP):用子类型替换父类型没有任何问题,用父类型替换子类型通常都是不行的。
接口隔离原则(ISP):接口要小而专,不能大而全。
合成聚合复用原则(CARP):优先考虑用强关联关系复用代码,而不是用继承关系复用代码。
迪米特法则(LoD):对象之间尽可能少的发生联系。
练习:五子棋
package com.lovoinfo; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.ImageIcon; import javax.swing.JDialog; @SuppressWarnings("serial") public class RenjuDialog extends JDialog { private RenjuPanel panel = new RenjuPanel(); public RenjuDialog() { this.setTitle("五子棋"); this.setSize(625, 645); this.setResizable(false); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); this.setIconImage(new ImageIcon("renju.png").getImage()); this.add(panel); this.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_F2) { panel.reset(); repaint(); } } }); } public static void main(String[] args) { new RenjuDialog().setVisible(true); } }
package com.lovoinfo; import java.awt.Color; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JPanel; import javax.swing.Timer; /** * 五子棋的面板 * @author jackfrued * */ @SuppressWarnings("serial") public class RenjuPanel extends JPanel { private Timer timer = null; private Board b = new Board(); // 创建棋盘对象 private boolean isBlack = true; // 是否黑方走棋 private boolean gameBegin = false; // 游戏是否开始 public RenjuPanel() { this.setSize(620, 620); this.addMouseListener(new MouseAdapter() { // 添加鼠标事件监听器监听鼠标按下事件 @Override public void mousePressed(MouseEvent e) { if(gameBegin) { int x = e.getX(); int y = e.getY(); if(x >= 20 && x <= 600 && y >= 20 && y <= 600) { int row = Math.round((y - 30) / 40.0f); int col = Math.round((x - 30) / 40.0f); if(b.move(row, col, isBlack)) { // 在鼠标点击位置走棋 isBlack = !isBlack; repaint(); } } } } }); timer = new Timer(1500, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int row = (int) (Math.random() * 15); int col = (int) (Math.random() * 15); if(b.move(row, col, isBlack)) { isBlack = !isBlack; repaint(); } } }); timer.start(); } @Override public void paint(Graphics g) { super.paint(g); // 绘制背景 g.setColor(Color.ORANGE); g.fillRect(0, 0, 620, 620); // 绘制棋盘 g.setColor(Color.BLACK); b.draw(g); } /** * 重置五子棋面板 */ public void reset() { timer.stop(); b.reset(); isBlack = true; gameBegin = true; } }
package com.lovoinfo; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; /** * 棋盘 * @author jackfrued * */ public class Board { private static final int CELL_SIZE = 40; private CellState[][] board = new CellState[15][15]; private int lastRow = -1, lastCol = -1; public Board() { reset(); } /** * 走棋 * @param row 落子的行 * @param col 落子的列 * @param isBlack 是不是黑棋 * @return 如果落子成功返回true否则返回false */ public boolean move(int row, int col, boolean isBlack) { if(board[row][col] == CellState.Empty) { board[row][col] = isBlack? CellState.Black : CellState.White; lastRow = row; lastCol = col; return true; } return false; } /** * 绘制棋盘和棋子 * @param g 画笔 */ public void draw(Graphics g) { // 纵横15道 for(int i = 0; i < board.length; i++) { g.drawLine(30, 30 + CELL_SIZE * i, 590, 30 + CELL_SIZE * i); g.drawLine(30 + CELL_SIZE * i, 30, 30 + CELL_SIZE * i, 590); } g.fillOval(305, 305, 10, 10); // 天元 Graphics2D g2d = (Graphics2D) g; g2d.setStroke(new BasicStroke(3)); // 将画笔变粗 g.drawRect(25, 25, 570, 570); // 外边框 // 对棋盘的行和列进行循环绘制棋子 for(int i = 0; i < board.length; i++) { for(int j = 0; j < board[i].length; j++) { if(board[i][j] != CellState.Empty) { // 不是空白 Color color = board[i][j] == CellState.Black? Color.BLACK : Color.WHITE; g.setColor(color); g.fillOval(10 + CELL_SIZE * j, 10 + CELL_SIZE * i, CELL_SIZE, CELL_SIZE); } } } if(lastRow != -1 && lastCol != -1) { g.setColor(Color.RED); g.drawLine(25 + CELL_SIZE * lastCol, 30 + CELL_SIZE * lastRow, 35 + CELL_SIZE * lastCol, 30 + CELL_SIZE * lastRow); g.drawLine(30 + CELL_SIZE * lastCol, 25 + CELL_SIZE * lastRow, 30 + CELL_SIZE * lastCol, 35 + CELL_SIZE * lastRow); } } /** * 重置棋盘 */ public void reset() { lastRow = -1; lastCol = -1; for(int i = 0; i < board.length; i++) { for(int j = 0; j < board[i].length; j++) { board[i][j] = CellState.Empty; } } } }
package com.lovoinfo; public enum CellState { Empty, Black, White }
相关文章推荐
- Java学习系列(十六)Java面向对象之基于TCP协议的网络通信
- 【连载】Java学习系列(006)——面向对象入门
- 【连载】Java学习系列(003)——程序逻辑-1(分支和循环)
- Java学习系列(十六)Java面向对象之基于TCP协议的网络通信
- Java学习系列(十六)Java面向对象之基于TCP协议的网络通信
- 【连载】Java学习系列(002)——数据类型和常用运算
- 【连载】Java学习系列(007)——继承和多态
- 【连载】Java学习系列(004)——程序逻辑-2(分支和循环)
- Java学习系列(十八)Java面向对象之基于UDP协议的网络通信
- 【连载】Java学习系列(005)——数组、方法和字符串
- Java基本知识(连载)-深入面向对象
- 深入Java系列——面向对象之(一)——抽象
- Java学习系列(十八)Java面向对象之基于UDP协议的网络通信
- 【云星数据---Apache Flink实战系列(精品版)】:Apache Flink高级特性与高级应用008-Slot和Parallelism的深入分析003
- Java学习系列(十八)Java面向对象之基于UDP协议的网络通信
- 【连载】Java学习系列(001)——Java概述和基本语法
- 深入了解ApusicAS服务器配置系列之——SSL配置
- 深入理解JavaScript系列(4) 立即调用的函数表达式
- [置顶] Java学习系列博客全目录
- 深入机器学习系列6-decision-tree