在软件系统中,类有多种类型,其中最常见的三种关系是依赖、聚合和继承

依赖的概念

依赖的思想就是一个类在某种程度上依赖于另外一个类。最常见的依赖就是一个类的方法调用另一个类的方法,这就已经建立了“使用”的关系。
通常,如果类A使用类B,则类A的一个(或多个)方法可以调用类B的一个(或多个)方法。如果被调用的类B的方法是静态的,那么要通过B的类名调用该静态方法。如果被调用类B的方法不是静态的,那么就要通过类B的实例调用该静态方法。也就是说,类A此时必须引用类B的对象。

这里关于静态类成员不太熟悉的小伙伴可以参考我上一篇关于静态类的博客:
https://blog.csdn.net/qq_63511424/article/details/123556921?spm=1001.2014.3001.5501

一个对象如何访问另一个对象是非常重要的设计决策。当一个类实例化另外一个类的对象时,就会发生类之间对象的访问。当然,将一个对象作为参数传递给另一个对象也会发生类之间对象的访问。
一般来说,我们需要最小化类之间的依赖关系。类之间相互依赖程度越低,变化产生的影响就越小,出错的概率就越低。(但对于我这样的初学者来说还是很远啦,小细节了解一下就好了~)

同一个类中对象的依赖

在某些情况下,类依赖自身。也就是说,一个类的对象与同一个类的另一个对象进行交互。为了实现同一类中对象的交互,类方法也可以接受用一个类的对象作为参数。
String类的concat方法就是一个很好的示例。执行concat方法时,将一个String对象作为参数传递给另外一个String对象👇
str3 = str1.concat(str2);
执行方法的String对象(str1)会将其字符与作为参数传递的String对象(str2)的字符相连,并将返回值作为新的String对象str3的字符加以保存。
以下名为RationalTester的程序也是类以来自身的示例。这里的ration有理数就是一个整数和另一个整数的比。RationTest程序创建了两个对象来表示有理数,然后执行各种操作生成新的有理数。

而关于有理数,这里我先贴出一段RationalNumber类的代码,方便小伙伴们理解,或者大家也可以去我另外一篇博客上浏览https://blog.csdn.net/qq_63511424/article/details/123588301?spm=1001.2014.3001.5502

  1. /**
  2. * Created with IntelliJ IDEA.
  3. * Description: Hello,I would appreciate your comments~
  4. * User: 葛玉礼
  5. * Date: 2022-03-19
  6. * Destination:有理数之间的运算
  7. */
  8. public class RationalNumber {
  9. private int numerator;//分子
  10. private int denominator;//分母
  11. public RationalNumber(int numer, int denom){
  12. if(denom == 0){
  13. denom = 1;
  14. }
  15. if(denom < 0){
  16. numer = numer * -1;
  17. denom = denom * -1;
  18. }
  19. numerator = numer;
  20. denominator = denom;
  21. reduce();//这个方法后面会写到
  22. }
  23. // 构建函数,用来初始化
  24. public int getNumerator(){
  25. return numerator;
  26. // 返回分子
  27. }
  28. public int getDenominator(){
  29. return denominator;
  30. // 返回分母
  31. }
  32. public RationalNumber reciprocal(){
  33. return new RationalNumber(denominator,numerator);
  34. // 这里返回值类型为本RationalNumber类返回值类型,分子分母位置调换,所以方法作用为返回倒数
  35. }
  36. public RationalNumber add(RationalNumber op2){
  37. int commonDenominator = denominator * op2.getDenominator();
  38. int numerator1 = numerator * op2.getDenominator();
  39. int numerator2 = op2.getNumerator() * denominator;
  40. int sum = numerator1 + numerator2;
  41. return new RationalNumber(sum,commonDenominator);
  42. // 和作为分子,分母之积作为分母
  43. }
  44. public RationalNumber subtract(RationalNumber op2){
  45. int commonDenominator = denominator * op2.getDenominator();
  46. int numerator1 = numerator * op2.getDenominator();
  47. int numerator2 = op2.getNumerator() * denominator;
  48. int difference = numerator1 - numerator2;
  49. return new RationalNumber(difference,commonDenominator);
  50. }
  51. // 以上为有理数的减法运算
  52. public RationalNumber multiply(RationalNumber op2){
  53. int numer = numerator * op2.getNumerator();
  54. int denom = denominator * op2.getDenominator();
  55. return new RationalNumber(numer,denom);
  56. }
  57. // 以上为有理数的乘法运算
  58. public RationalNumber divide (RationalNumber op2){
  59. return multiply(op2.reciprocal());
  60. // 有理数的除法,除一个数则是乘这个数的倒数
  61. }
  62. public boolean isLike(RationalNumber op2){
  63. return (numerator == op2.getNumerator()&&denominator == op2.getDenominator());
  64. }
  65. // 确定此有理数是否等于作为参数传递的有理数,假设在两者都被化简过的情况下
  66. public String toString (){
  67. String result;
  68. if (numerator == 0){
  69. result = "0";
  70. }else if(denominator == 1){
  71. result = numerator +"";
  72. }else {
  73. result = numerator + "/" + denominator;
  74. }
  75. return result;
  76. // 将有理数转化为字符串
  77. }
  78. private void reduce(){
  79. if(numerator != 0){
  80. int common = gcd(Math.abs(numerator),denominator);
  81. numerator = numerator / common;
  82. denominator = denominator / common;
  83. }
  84. }
  85. // 重要的动作:化简,这里的gcd为返回最大公因数
  86. private int gcd(int num1, int num2){
  87. while (num1 != num2){
  88. if(num1>num2){
  89. num1 = num1 - num2;
  90. }else {
  91. num2 = num2 - num1;
  92. }
  93. }
  94. return num1;
  95. }
  96. }

那么了解完RationalNumber类之后,我们来做一个测试,以此更好的理解

  1. /**
  2. * Created with IntelliJ IDEA.
  3. * Description: Hello,I would appreciate your comments~
  4. * User: 葛玉礼
  5. * Date: 2022-03-19
  6. * Destination:这是一个利用有理数方法来解释依赖概念的类
  7. */
  8. public class RationalTest {
  9. // 我们进一步利用有理数的类中的方法来解释我们的概念
  10. public static void main(String[] args) {
  11. RationalNumber r1 = new RationalNumber(6,8);
  12. RationalNumber r2 = new RationalNumber(1,3);
  13. RationalNumber r3, r4, r5 ,r6, r7;
  14. System.out.println("First rational number:" + r1);
  15. System.out.println("Second rational number:" + r2);
  16. if(r1.isLike(r2)){
  17. System.out.println("r1 and r2 are equal.");
  18. }else {
  19. System.out.println("r1 and r2 are not equal.");
  20. r3 = r1.reciprocal();
  21. r4 = r1.add(r2);
  22. r5 = r1.subtract(r2);
  23. r6 = r1.multiply(r2);
  24. r7 = r1.divide(r2);
  25. System.out.println("r1 + r2 = " + r4);
  26. System.out.println("r1 - r2 = " + r5);
  27. System.out.println("r1 * r2 = " + r6);
  28. System.out.println("r1 / r2 = " + r7);
  29. }
  30. }
  31. }

输出为

First rational number:3/4 Second rational number:1/3 r1 and r2 are not equal. r1 + r2 = 13/12 r1 - r2 = 5/12 r1 * r2 = 1/4 r1 / r2 = 9/4

那么,了解完了这串代码之后,我们再回到依赖这个概念的理解,进行一个RationalNumber的测试。在我们分析这个类时,要知道这个类创建的对象代表有理数,RationalNumber类包含有有理数的各种运算,如加减乘除,在此并没有调用String对象是否相等的equal方法,因其带有继承概念,为了避免混淆,所以采用isLike的方法。要注意的是,RationalNumber类中的一些方法,如reduce和gcd,都声明为私有可见性。这些方法都是私有的,因此我们并不希望从RationalNumber外部执行这些方法。这些方法的存在只是为了支持对象的一些其他服务。

聚合

有些对象由其他对象组成。例如:汽车由车身,轮胎,发动机组成
任何组成部件都是独立的对象。因此,我们可以说汽车是一种集合,它由其他对象组成。
集合是一种”has a “关系,例如 A car has a light.

重要概念: 聚合对象由其他对象组成,形成has-a关系

在软件世界中,聚合对象是将对其他对象的引用作为实例数据的对象。例如,Account对象包含了String对象,而String对象表示账户所有者的姓名。又是,我们会忘记String是个对象,但正因为String是对象,才使得每个Account对象都成为了聚合对象。
聚合是一直特殊的依赖关系。也就是说,一个类的组成部分由依赖于该类的另一个类定义。聚合对象的方法会调用其组成对象的方法。
对象越复杂,就越可能要用聚合对象来表示。

this的引用

这部分的知识我在静态类成员的博客中有所提到,感兴趣的小伙伴可以再去瞅两眼
https://blog.csdn.net/qq_63511424/article/details/123556921?spm=1001.2014.3001.5501
我在这里稍微总结一下:
在非静态方法内,可以使用this来引用当前执行的对象
在同一类中调用其他方法,直接调用即可,编译器会自动添加
this不能用于静态方法(例如main方法)
我们通常用this来引用区分构造函数的参数和同名的实例变量。
举个简单的例子:

public Account (String name, long acctNumber, double balance){ name = name; acctNumber = acctNumber; balance = balance; }

当我们编写这个构造函数的时候,我们一般会使用不同的参数名,意图去与实例变量name、acctNumber和balance区分开来,使用this实现方法如下:

public Account (String name, long acctNumber, double balance){ this.name = name; this.acctNumber = acctNumber; this.balance = balance; }

在这类的构造函数中this引用就是引用对象的实例变量。赋值语句右边的变量是形参。这种方法消除了形参和实例变量同名的现象。这种问题一般在构造函数中最常见。
PS:关于构造函数,我在之前的博客中也有介绍,不太了解的小伙伴可以进去瞅两眼👉
https://blog.csdn.net/qq_63511424/article/details/123551699?spm=1001.2014.3001.5502
现在是凌晨3点22分了,今天也是我的生日,希望自己以后可以继续努力下去,晚安。