面向对象程序设计第一单元总结

学习体会:

  第一单元的学习主要围绕雨刷器的例子来初步认识面向对象的概念。学习类之间的关系,各类关系的作用,让我们从设计者的角度思考问题,运用类之间的关系来合理的进行设计。通过不断地学习面向对象程序设计的原则,对代码进行迭代,使代码符合面向对象程序设计的原则。面对快节奏的学习,我不能只是被动接受老师的知识,更多是自主地学习。运用网络上的资源,提前做好预习工作。

雨刷器01

主要内容:使用C语言函数的方法解决雨刷器问题,没有涉及到面向对象程序设计。

优点:没什么优点。

缺点:代码耦合性高,内聚性低,不可拓展,不可复用,不符合面向对象程序设计的原则。

雨刷器02

主要内容:在设计时,我设计了六个类,分别是Brush, Dial, Driver, Lever, Main, Control。尝试使用单一职责原则。

 

 

类图如下:

 

 

优点:从实际角度出发,合理地设计了类内属性,将Dial, Lever和Brush三个类通过与一个业务类Control建立关联关系来对它们进行解耦操作。

缺点:类内的函数依然没有实现单一职责原则,代码拓展性低,类之间的关系仍然不合理。

 

 

雨刷器03

主要内容:基于雨刷器02的类的设计,改进了类之间的关系,解耦更加充分,类之间的关系设计得也更加合理,增加了Input和Output类来实现单一职责原则

类图如下:

 

 

 优点 :实现单一职责原则与迪米特法则,充分解耦。

缺点:代码可拓展性不高,不符合MVC模式。

雨刷器04

主要内容:基于雨刷器03进行迭代,结合MVC设计模式,并对Driver,Dial, Brush, Lever类单例化处理。

类图如下:

 

 

 

 

优点:符合单一职责原则与迪米特法则,MVC设计模式,合理单例化了类,使得代码更加符合逻辑。

缺点:代码的可拓展性依然没有得到提升。

BrushSystemPro

主要内容:使用了继承和多态的方法,对雨刷器04的代码进行了重构

类图如下:

 

 

 

优点:在雨刷器04的基础上对Brush,Lever,Dial类写成了抽象类,类中的方法也重构成了抽象方法 ,再通过继承的方式来具体添加符合用户要求的配件。代码可拓展性高。

缺点 :如果需要更换配件,依然需要更改主方法中的代码,不符合开闭原则。

以上是围绕雨刷器示例进行的实验以及总结

 


 

知识点回顾

 面向对象设计原则:

1.单一职责原则(SRP:Single responsibility principle)(提出者:Robert C. Martin):
  一个类应该只有一个发生变化的原因。(解耦, 增强内聚性)

2.开闭原则(OCP:Open Closed Principle):
  要求开放扩展(extend),关闭修改(modification)。
  1)梅耶开闭原则:一旦完成,一个类的实现只应该因错误而修改,新的或者改变的特性应该通过建立不同的类实现。
  新建的类可以通过继承的方式来复用原类的代码。衍生的子类可以或不可以拥有与原类相同的接口。
  2)多态开闭原则:在20世纪90年代,开闭原则被广泛的重新定义。由于抽象化接口的使用,在这中间实现可以被改变,
  多种实现可以被创建,并且多态化的替换不同实现。
  相比梅耶的使用方式,多态开闭原则的定义倡导对抽象基类的继承。接口规约可以通过继承来重用,但是实现不必重用。
  已存在的接口对于修改是封闭的,并且新的实现必须,且至少实现那个接口。

3.里式代换原则(LSP:Liskov Substitution principle)(提出者:Barbara Liskov):
  派生类(子类)对象可以在程式中代替基类对象
  circle.fun();
  shape.fun(); // 两行代码都得能执行;
  子类的方法父类也必须有。


4.合成复用(CRP:Composite Reuse Principle)(组合/聚合复用原则(CARP)):
  在软件复用时,要尽量组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
  如果要使用继承关系,必须严格遵守里式代换原则。
  (合成复用原则同里式代换原则相辅相成,两者都是开闭原则具体实现规范。)


5.依赖倒转 (DIP:Dependence inversion Principle)(依赖倒置):
  两个类之间有依赖关系时,要依赖抽象,不要依赖具体。
  依赖于接口,不要依赖于具体实现。
  要求对抽象进行编程,不要对实现进行编程。


6.迪米特原则(最少知识原则)(提出者:Lan Holland)(LOD):
  一个类对于其他类知道的越少越好, 就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,
  不和陌生人说话。

7.接口隔离原则(ISP:interface Segregation Princple):
  一个接口里的方法越少越好。
(以下是几种对接口隔离原则的几种不同的阐述)
  使用多个专门的接口比使用单一的总接口要好。

  一个类对另外一个类的依赖性应当式建立在最小接口上的。

  一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,
  形成一个臃肿的大接口,这是对角色和接口的污染。

  “不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。”
  这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫客户使用它们不使用的方法,
  那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。

 


 

 封装

封装的介绍
  封装(encapsulation)就是把抽象出的数据(属性)和对数据的操作(方法)
封装在一起,数据呗保护在内部,程序的其他部分只有通过被授权的操作(方法)
才能对数据进行操作。

封装的理解和好处
  1.隐藏实现的细节
  2.可以对数据进行验证,保证安全合理

封装的实现步骤
  1.将属性进行私有化
  2.提供setter和getter

注:如果想防止通过构造方法对属性进行非法赋值的情况,
可以在有参的构造方法里调用含有检查数据合法性的set方法

 


 

继承

// 为什么需要继承
代码的复用,实现多态。


//泛化关系/继承/复用

public class A {
private int no;
protected String name;
int age; // default

public A() {
}

public A(int no, String name) {
this.no = no;
this.name = name;
}

public int getNo() {
return this.no;
}

public void setNo(int no) {
this.no = no;
}

public String getName() {
return this.name;
}

public void setName (String name) {
this.name = name;
}

class B extends A{ // A父类(基类)(super class超类), B子类(派生类)
private String phoneNo;

public B(){
}


public B(int no, String name, String phoneNo) {
super(no, name); // super (父类的引用) this(当前对象的引用)
this.phoneNo = phoneNo;
}
}

// 抽象类(不能实例化对象)
abstract class Shape{
private String color;

public Shape(){
}

public Shape(String color) {
this.color = color;
}

public String getColor() {
return this.color;
}

public void setColor(String color) {
this.color = color;
}

public abstract double getArea();
}

// 抽象类不能实例化,但是可以作为父类

class Circle extends Shape {
private double radius = 0;

public Circle(){
}

public Circle(Sstring color, double radius) {
super(color);
this.radius = radius;
}

public double getRadius() {
return this.radius;
}

public void setRadius(double radius) {
this.radius = radius;
}

@Override // 复写父类的方法
public double getArea(){
return Math.PI * this.radius * this.radius;
}

}

class Ball extends Circle {

public Ball(){
}

public Ball(Sting color, double radius) {
super(color, radius);
}

@Override
public double getArea() {
return 4 * super.getArea();
}
}

Circle circle = new Circle();
circle.getArea();

Shape shape = new Circle();
System.out.println(shape.getArea());

shape = new Ball("black", 5.4);
System.out.println(shape.getArea());

// 多态(不同的对象接受同一消息时产生不同的操作)

void fun(Shape shape){
System.out.println(shape.getArea());
}

fun(circle);

fun (ball);


 

类库的学习

List

ArrayList 类 // 列表
// 变长数组
ArrayList list = new ArrayList();
list.add(23);
list.add(12.3);
list.add("abc");
// list.size() 返回数组长度
// list.get(index) 获取index位置的元素
// list可以直接输出
// list 可以储存不同数据类型的数据

LinkedList 类 // 动态存储的列表
// 基本操作与ArryList 一致
// 可以指定列表中的数据类型
LinkedList<Intrger> list = new LinkedList<Integer>();
// 泛型:把类型作为参数
LinkedList<这里不能是基本数据类型>

String

String 类
// 装箱,拆箱
// 定长字符串

String str = new String("abc");
String str = "abc";
String str2 = "abc";
String str3 = "abc";
// 同样的字符串只申请一个内存空间

str = "123" + str;
// 容易内存泄漏


StringBuffer 类
// 变长字符串,线程安全的。效率比String低
StringBuffer sb1 = new StringBuffer();

sb1.append("abc");// 追加
sb1.append("123");


StringBuilder 类
// 线性不安全,效率略高于StringBuffer
StringBuilder sb2 = new StringBuilder();


 单元小结

   学习心得:在这两周的学习中,最明显的感受就是节奏很快,想要能够灵活运用所学的知识需要大量的时间去练习。作业难度也在逐渐提升,需要合理地去规划学习地时间

才能做到各个学科之间的平衡。

  近期目标:希望能够跟上课程进度,并且尽可能地自主学习其他知识,拓宽知识面,学习JAVA中的更多工具。

posted @ 2022-04-03 23:35  哦嘞里个嘞  阅读(83)  评论(0)    收藏  举报