设计模式:面向对象
面向对象编程:以类或对象作为组织代码的基本单元,将封装、抽象、继承、多态,作为代码设计和实现的基石。
面向对象编程语言:支持类或对象的语法机制,能方便的实现上述四大面向对象特性的编程语言。
封装/抽象/继承/多态 可以解决的编程问题
封装(Encapsulation)
封装也叫做数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息或数据。
封装的意义:如果对类中的属性访问不做限制,任何代码都可以访问、修改类中的属性,这就会造成数据的不可控,属性可以随意的被修改。此外,通过有限的方法暴露必要的操作,也能提高类的易用性。如果把类的属性都暴露给类的调用者,他需要对业务细节有足够了解才能正确操作这些属性。
抽象(Abstraction)
抽象说的是如何隐藏方法的具体实现,让调用者只需要关心方法提供了哪些功能,而并不需要知道这些功能是如何实现的。
继承(Inheritance)
继承用来表示类之间is-a的关系。
继承的意义:继承最大的好处是代码复用。假如两个类有相同的属性和方法,可以将相同的部分,抽取到父类中,这样两个子类就可以重用父类中的代码。
过渡使用继承,继承层次过深,会导致代码可读性、可维护性变差。
多态(Polymorphism)
多态是指,子类可以替换父类,在实际代码运行中,调用子类的方法实现。
多态的意义:提高代码的扩展性和复用性,是很多设计模式、设计原则、编程技巧的代码实现基础。
面向过程与面向对象
什么是面向过程编程
面向过程编程以方法、函数作为组织代码的基本单元,以数据(成员变量、属性)与方法相分离为最主要特点。面向过程风格是一种流程化的编程风格,通过拼接一组顺序执行的方法来操作数据完成一项功能。
面向过程与面向对象最主要的区别是,代码的组织方式不同。面向过程风格的代码被组织成了一组方法集合及其数据结构,方法和数据结构定义是分开的。面向对象风格代码被组织成一组类,方法和数据结构被绑定一起,定义在类中。
面向对象编程的优势
1.更能应对大规模复杂程序的开发;
- 大规模复杂程序中,处理流程并非一条单一的主线,而是错综复杂的网状结构;
2.具有更加丰富的特性,更加易扩展、易复用、易维护;
- 利用了封装、抽象、多态、继承;
3.更加人性化、高级且智能。
- 面向过程编程更加贴近机器的思维方式,而面向对象编程更加贴近人;
错误的面向对象编程
1.滥用getter、setter方法
public class ShoppingCart{
private int itemsCount;
private List<Item> items = new ArrayList<>();
public void setItemsCount(int itemCount) {
this.itemCount = itemsCount;
}
public List<Item> getItems() {
return this.items;
}
}
这里定义了private变量,但是提供了public setter方法,这就跟将这个属性定义为public没什么区别了。
所以,我们不应该暴露不该暴露的setter方法。
对于items属性,虽然没有提供setter方法,但因为它是一个集合容易,外部可以拿到这个容器后,修改里面的数据。这就会造成items和itemsCount的不一致。
所以,如果需要知道items里面有什么,我们需要通过返回不能被修改的容易方法。
public List<Item> getItems() {
return Collections.unmodifiableList(this.items);
}
2.滥用全局变量和全局方法
常见的全局变量:单例类对象、静态成员变量、常量等;
全局方法:静态方法,常用的Utils类。
下面通过Constants类的定义来探讨全局变量的利与弊:
public class Constants {
public static final String MYSQL_ADDR = "mysql_addr";
public static final String MYSQL_DB = "db_name";
// ...更多常量定义...
}
把所有的常量,都集中放到一个Constants类中,不是很好的设计:
- 影响可维护性:类会越来越大。
- 增加代码编译时间:这个类会被很多别的类依赖,每次修改该类,都会导致依赖它的类文件重新编译。
- 影响代码复用性:假如在另一个项目中复用本项目某个类,但这个类又依赖Constans类,即使只用到Constants类中的一小部分变量,也需要把整个类都引入。
如何改进?
- 拆分;
- 不单独使用常量类,而是哪个类用到某个常量,将其定义到这个类中。