目录
1、单一职责原则
每个方法、类、框架都只负责一件事情。
/**
* 反例:
* 统计一个文本文件中,有多少字符,所有功能在一个方法里
*/
public class Test {
public static void main(String[] args) throws Exception {
Reader in = new FileReader("d:\\a.txt");
BufferedReader br = new BufferedReader(in);
String line = null;
StringBuilder sb = new StringBuilder("");
while ((line = br.readLine()) != null) {
sb.append(line)
.append("\n");
}
br.close();
in.close();
String[] words = sb.toString().split("[^a-zA-Z]+");
System.out.println(words.length);
}
}
以上代码,违反了单一职责,缺点:拓展功能时,代码重用性低,代码可读性低
// 读取txt文件
private static String str(String path) throws Exception {
Reader in = new FileReader(path);
BufferedReader br = new BufferedReader(in);
String line = null;
StringBuilder sb = new StringBuilder("");
while ((line = br.readLine()) != null) {
sb.append(line)
.append("\n");
}
br.close();
in.close();
return sb.toString();
}
// 按特殊字符分割单词
private static String[] getWords(String s) {
String[] words = s.toString().split("[^a-zA-Z]+");
return words;
}
public static void main(String[] args) throws Exception {
String sb = str("d:\\a.txt");
String[] words = getWords(sb);
System.out.println(words.length);
}
上述代码,符合单一职责
2、开闭原则
a、对扩展新功能开放 b、对修改原有功能关闭
3、接口隔离原则
来自百度百科解释:
- 客户端不应该依赖它不需要的接口
- 类间的依赖关系应该建立在最小的接口上
4、依赖倒置原则
程序要依赖于抽象接口,不要依赖于具体实现。
违反原则时:
class Person {
public void feed(Dog dog) {
System.out.println("开始喂狗。。。");
dog.eat();
}
}
class Dog {
public void eat() {
System.out.println("狗开始吃。。。");
}
}
class Cat {
public void eat() {
System.out.println("猫开始吃。。。");
}
}
// 当新增一个动物喂养时,无法满足
public class Test {
public static void main(String[] args) {
Person p = new Person();
Dog d = new Dog();
p.feed(d);
Cat c = new Cat();
p.feed(c); // 报错,无法实现,需要修改
}
}
满足原则:
class Person {
public void feed(Animal animal) {
System.out.println("开始喂。。。");
animal.eat();
}
}
interface Animal {
void eat();
}
class Dog implements Animal {
public void eat() {
System.out.println("狗开始吃。。。");
}
}
class Cat implements Animal {
public void eat() {
System.out.println("猫开始吃。。。");
}
}
public class Test {
public static void main(String[] args) {
Person p = new Person();
Dog d = new Dog();
p.feed(d);
Cat c = new Cat();
p.feed(c);
}
}
5、迪米特法则(最少知道原则)
迪米特法则,也叫最少知道原则(封装) 一个类,对于其他类,要知道的越浅越好 强调只和朋友说话,不和陌生人说话。 注:朋友指的是出现在成员变量、参数、返回值的类,而出现在方法体内部的类不属于
反例:
public class Test {
public static void main(String[] args) {
Foo f = new Foo();
Bar bar = f.get();
bar.t1();
}
}
class Bar {
public String t1(){
return "";
}
}
class Foo {
public Bar get(){
return new Bar();
}
}
Foo是Test类的朋友,但Bar是Test类的陌生人。
6、里氏替换原则
任何能使用父类对象的地方,都应该能透明的替换为子类对象
1)子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
2)子类中可以增加自己特有的方法。
3)当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
4)当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
举例说明:点击这里
7、组合优于继承
需求:制作一个集合,要求该集合能记录至今为止添加过多少个元素
public class Test {
public static void main(String[] args) {
MySet set = new MySet();
Set set2 = new HashSet();
set2.add("测试");
set2.add("集合");
set2.add("添加");
set.addAll(set2);
System.out.println(set.getCount());
}
}
class MySet extends HashSet {
private int count = 0;
public boolean add(Object o) {
count++;
return super.add(o);
}
public boolean addAll(Collection c) {
count += c.size();
return super.addAll(c);
}
public int getCount() {
return count;
}
}
存在问题:addAll会回调add方法,导致统计个数不对。
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
由问题分析可知,父类HashSet addAll调用了add,所以将子类的addAll重写去除,好像这样就可以实现该功能。但这样真的可行吗?
注:如若HashSet addAll不再调用add时,将会导致该子类再一次错误。
那这里进一步修改addAll,让其不再调用父类的:
public boolean addAll(Collection c) {
boolean flag = false;
for(Object o : c) {
if(add(o)) {
flag = true;
}
}
return flag;
}
这种方式可以解决父类addAll方法被修改的问题,但是一旦父类新增了一个add相关的方法,这时由于子类MySet没有对其修改就会导致无法实现统计已添加元素的个数。
由上分析,这里的MySet不再去继承HashSet了,而是让MySet和HashSet发生关联关系:
class MySet {
private int count = 0;
private Set set = new HashSet();
public boolean add(Object o) {
count++;
return set.add(o);
}
public boolean addAll(Collection c) {
count += c.size();
return set.addAll(c);
}
public int getCount() {
return count;
}
}