允许对类进行继承扩展,不允许对源代码进行修改。例如水果工厂类中每增加一个水果,都要对水果工厂类进行修改,重新编译。如果水果工厂类FruitFactory只是定义接口生产水果,苹果applefactory、梨子pearfactory等工厂类单独实现fruitfactory接口类,创建不同的水果对象,各种水果的创建互不影响,新增水果,只要新增一种水果类继承fruitfactory,不会对fruitfactory类进行修改,这就是对扩展开发,对修改关闭。
interface FruitFactory{
void produceFruit();
}
class AppleFactory implements FruitFactory{
public void produceFruit() {
System.out.println("生产苹果");
}
}
class PearFactory implements FruitFactory{
public void produceFruit() {
System.out.println("生产苹果");
}
}
其核心就是面向接口编程,即当调用的类可能会拓展时用接口代替相应的类。
未使用依赖倒置:
interface BuyGoods{
void buy();
}
class BuyQingcai implements BuyGoods{
public void buy() {
System.out.println("买青菜");
}
}
class People {
public void buy(BuyQingcai buyGoods){
buyGoods.buy();
}
}
public class Test2 {
public static void main(String[] args) {
People p = new People();
p.buy(new BuyQingcai());
}
}
上述看着没什么问题,但是如果他不想买青菜,想买萝卜怎么办?我们当然可以新建一个萝卜类,再给他弄一个buy方法,但是问题是People并没有操作萝卜类的方法,我们还需要在People添加对萝卜类的依赖。这样代码要修改的代码量太多了,模块与模块之间的耦合性太高,只要需要稍微有点变化,就要大面积重构,所以该设计不合理。
使用依赖倒置:
interface BuyGoods{
void buy();
}
class BuyQingcai implements BuyGoods{
public void buy() {
System.out.println("买青菜");
}
}
class People {
public void buy(BuyGoods buyGoods){
buyGoods.buy();
}
}
public class Test2 {
public static void main(String[] args) {
People p = new People();
p.buy(new BuyQingcai());
}
}
一个类或者一个方法只负责一项职责,尽量做到类的只有一个行为原因引起变化。如A类只负责功能A,B类只负责功能B,不要让A类既负责功能A,又负责功能B,这样会导致代码混乱,容易产生bug。
将接口细化**,**类继承接口,类中不需要实现不需要的接口。
最小关系原则,也就是说如果一个代码块能独立封装在一个类的函数中则最好不要放在调用处。
反例如下:
import java.util.ArrayList;
import java.util.List;
class Employee{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
class SubEmployee {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
class SubEmployeeManager {
public List<SubEmployee> setValue(){
List<SubEmployee> subEmployees=new ArrayList<SubEmployee>();
for(int i=0;i<10;i++){
SubEmployee subEmployee=new SubEmployee();
subEmployee.setId("分公司"+i);
subEmployees.add(subEmployee);
}
return subEmployees;
}
}
class EmployeeManager {
public List<Employee> setValue(){
List<Employee> employees=new ArrayList<Employee>();
for(int i=0;i<10;i++){
Employee employee=new Employee();
employee.setId("总公司"+i);
employees.add(employee);
}
return employees;
}
public void printAllEmployee(SubEmployeeManager sub){
List<SubEmployee> list1 = sub.setValue();
for(SubEmployee e:list1){
System.out.println(e.getId());
}
List<Employee> list2 = this.setValue();
for(Employee e:list2){
System.out.println(e.getId());
}
}
}
EmployeeManager的printAllEmployee函数中,此段代码违背了迪米特法则,应该放在SubEmployee中实现:
List<SubEmployee> list1 = sub.setValue();
for(SubEmployee e:list1){
System.out.println(e.getId());
}
使用迪米特原则:
import java.util.ArrayList;
import java.util.List;
class Employee{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
class SubEmployee {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
class SubEmployeeManager {
public List<SubEmployee> setValue(){
List<SubEmployee> subEmployees=new ArrayList<SubEmployee>();
for(int i=0;i<10;i++){
SubEmployee subEmployee=new SubEmployee();
subEmployee.setId("分公司"+i);
subEmployees.add(subEmployee);
}
return subEmployees;
}
public void printAllSubEmployee(){
List<SubEmployee> list1 = setValue();
for(SubEmployee e:list1){
System.out.println(e.getId());
}
}
}
class EmployeeManager {
public List<Employee> setValue(){
List<Employee> employees=new ArrayList<Employee>();
for(int i=0;i<10;i++){
Employee employee=new Employee();
employee.setId("总公司"+i);
employees.add(employee);
}
return employees;
}
public void printAllEmployee(SubEmployeeManager sub){
sub.printAllSubEmployee();
List<Employee> list2 = this.setValue();
for(Employee e:list2){
System.out.println(e.getId());
}
}
}
尽量不使用继承,而是通过过定义接口I,类A实现接口,在需要使用A类的B类中定义接口引用I的对象,通过传入A类,可以在B中调用通过接口I对象调用A的实现方法。通过这种方式,可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
import java.util.ArrayList;
import java.util.List;
interface Print{
void out();
}
class A implements Print{
public void out() {
System.out.println("AAAAAA");
}
}
class B {
private Print print;
void setPrint(Print print){
this.print = print;
}
public void output(){
if(print != null)
print.out();
}
}
public class Test2{
public static void main(String[] args) {
B b = new B();
b.setPrint(new A());
b.output();
}
}
小结: