面向对象三大特性之封装

鉴于很多初识面向对象编程的同学对面向对象中封装特性的不理解,今天特写下此篇博文,以供参考。  

 

什么是封装?

除了保护对象的数据不受非法修改外,强制使用者通过方法老访问数据是确保方法调用后各数据仍合法的更简单的方法。(Java程序设计 第二版)

 

Java对封装的支持

Java中提供了包、public、protected、private和default来实现访问控制,但有的同学不理解什么时候应该用什么关键字比较合理。下面用一个例子来讲解。

 

问题描述

现在有一个学生成绩管理系统,使用者包括学生和老师,使用者的权限如下

学生:

1、查看学生的各科成绩

2、查看学生的平均成绩

老师:

1、给学生的各科成绩打分

2、查看学生的各科成绩

3、查看学生的平均成绩

老师和学生的区别在于老师可以修改学生的考试成绩,而学生只能查看成绩。

 

现在包结构设计图如下:

(Student)学生类是学生对成绩的操作。

(Teacher)教师类是教师对学生成绩的操作。

(StudentExamResult)成绩类是学生的成绩。

(StudentManagement)成绩管理类实现对学生信息的维护。

 

StudentExamResult设计如下:

 1 package teacher;
 2 
 3 public class StudentExamResult {
 4     //学生各科成绩
 5     private int math = 0;
 6     private int chinese = 0;
 7     private int english = 0;
 8     
 9     //公有方法对老师和学生都开放
10     public float getAverage(){
11         return (math + chinese + english)/3;
12     }
13     public int getMath(){
14         return math;
15     }
16     public int getChinese() {
17         return chinese;
18     }
19     public int getEnglish() {
20         return english;
21     }
22     
23     //保护方法只对老师开放
24     protected void setMath(int math){
25         this.math = math;
26     }
27     protected void setChinese(int chinese) {
28         this.chinese = chinese;
29     }
30     protected void setEnglish(int english) {
31         this.english = english;
32     }
33 }

StudentExamResult类中定义了三个私有的成绩属性,四个公有的Get方法,三个保护Set方法。

 

StudentManagement设计如下:

 1 package system;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 
 6 import teacher.StudentExamResult;
 7 
 8 public class StudentManagement {
 9     private static Map<String,StudentExamResult> studentExamResults = new HashMap<String,StudentExamResult>();
10     
11     static{
12         studentExamResults.put("20100230101", new StudentExamResult());
13         studentExamResults.put("20100230102", new StudentExamResult());
14         studentExamResults.put("20100230103", new StudentExamResult());
15         studentExamResults.put("20100230104", new StudentExamResult());
16     }
17     
18     public static StudentExamResult getStudentExamResultById(String id){
19         return studentExamResults.get(id);
20     }
21 }

StudentManagement类维护学生的成绩信息,在这里只是做了一个模拟,表示老师和学生都从数据库或者其他存储介质得到学生对象,没有实际作用。

 

Student设计如下:

 1 package student;
 2 
 3 import system.StudentManagement;
 4 import teacher.StudentExamResult;
 5 
 6 public class Student {
 7     public static void main(String[] args) {
 8         StudentExamResult myResult = StudentManagement.getStudentExamResultById("20100230101");
 9         if(null == myResult){
10             System.out.println("此学生不存在!");
11         }else{
12             System.out.println("我的数学成绩是:" + myResult.getMath());
13             System.out.println("我的语文成绩是:" + myResult.getChinese());
14             System.out.println("我的英语成绩是:" + myResult.getEnglish());
15             System.out.println("我的平均成绩是:" + myResult.getAverage());
16         }
17     }
18 }

学生通过get方法获得成绩属性

 

Teacher类设计如下:

 1 package teacher;
 2 
 3 import system.StudentManagement;
 4 
 5 public class Teacher {
 6     public static void main(String[] args) {
 7         StudentExamResult myStudent = StudentManagement.getStudentExamResultById("20100230101");
 8         if(null == myStudent){
 9             System.out.println("该学生不存在!");
10         }else{
11             //给学生打分
12             myStudent.setMath(90);
13             myStudent.setEnglish(90);
14             myStudent.setChinese(90);
15             System.out.println("该学生的平均成绩是:"+myStudent.getAverage());
16         }
17     }
18 }

老师通过set方法设置学生成绩

 

重点来了,以问答的形式来进行讲解:

1.为什么把属性定义成private的,定义成public会怎样?

根据需求,学生用户只能查看各科成绩和平均成绩,如果把成绩属性定义成public,那么老师可以通过myStudent.math = xx设置学生的成绩,学生也可以通过myResult.math = xx,改变成绩的值,这是不允许的。所以这里将成绩属性设置成private的,而只提供方法来访问成绩属性,我们只需要对方法来进行访问控制就行了。

2.为什么要定义protected方法,如何访问?

首先,protected方法的访问范围是【本类、本包和所有子类】,那么我们再看,现在Teacher类和StudentExamResult类在同一个包中,所以Teacher类可以通过myStudent.setMath(XX)来设置学生的数学成绩,Student类和StudentExamResult类不在同一个包中,想通过myResult.setMath(XX)来设置成绩是不可能的,编译器根本就不能编译通过,因为setMath方法在这里不可见。

这样就实现了老师可以修改学生成绩而学生只能查看成绩。

3.在一般的设计中为什么总是把成员变量设置为private的?

private的访问范围是【本类中】,只允许本类的方法直接访问private属性,在进行业务处理时只提供接口给外部,这样可以保证数据的有效性和正确性。

举个例子

 1 class MyDate{
 2     private int year = 2014;
 3     private int month = 1;
 4     private int day = 1;
 5     
 6     /**
 7      * 返回当前月的下一个月,例如当前月是10月,则返回11;如果当前月是12月则返回1。
 8      * @return 下一月的月数
 9      */
10     public int nextMonth(){
11         int nextMonth = 0;
12         if(12 == month){
13             nextMonth = 1;
14         }else{
15             nextMonth++;
16         }
17         return nextMonth;
18     }
19 }

 

使用者想获得下一个月的月数,直接调用nextMonth方法就可以了,假设把month定义为public的,那么就会把复杂的业务逻辑交给用户去处理,而且无法保证数据的合理性。

 

下面附上java访问控制修饰符的控制范围

作用域
当前类
同一package
 
子孙类
 
其他package
public
       
protected
       ×
default
   ×  ×
private
   ×  ×  ×

 

 

 

 

 

 

 

 

第一次写博客,不妥之处,还请见谅!

 

 

posted @ 2014-05-19 16:03  Wesley Dai  阅读(80)  评论(0)    收藏  举报