六大原则
设计原则只是说设计更合理,不按照设计原则的套路来并不是代码错误或者实现不了功能。敲了这么多年的代码,要学会优雅。
1、开闭原则
一个模块、一个类或一个方法,应该对扩展开放,对修改关闭。
比如一个方法,如果有新的内容需要判断,如果要修改这个类,那就是违背了这个原则。如果能够做到无缝扩展,那就是符合这个原则。
反例:
public class PieChart {
public void display() {
System.out.println("pie chart");
}
}
public class BarChart {
public void display() {
System.out.println("bar chart");
}
}
ChartDisplay 对外承接一切调用:
public class ChartDisplay {
void display(int type){
if(type == 1){
PieChart pieChart = new PieChart();
pieChart.display();
} else if(type == 2){
BarChart barChart = new BarChart();
barChart.display();;
}
}
}
客户端调用:
public static void main(String[] args){
ChartDisplay chartDisplay = new ChartDisplay();
chartDisplay.display(1);
chartDisplay.display(2);
}
这种情况,如果再加扩展WifiChart,那就要修改ChartDisplay类,对外接口不宜改动,不然哪里有幺蛾子也不晓得呀。
正例:
抽象一个父类
public abstract class AbstractChart {
public abstract void display();
}
PieChart、BarChart具体实现
ChartDisplay 对外承接一切调用:
public class ChartDisplay {
AbstractChart chart;
ChartDisplay(AbstractChart chart){ 这是个抽象类 verygood
this.chart = chart;
}
void display(){
chart.display();
}
}
客户端调用,客户端你自己决定调用啥,不要接口方来区分:
public static void main(String[] args){
ChartDisplay chartDisplay = new ChartDisplay(new PieChart());
chartDisplay.display();
chartDisplay = new ChartDisplay(new BarChart());
chartDisplay.display();
}
这样扩展一个WifiChart,只需要继承抽象父类,由客户端自己决定调用,不会修改ChartDisplay。
2、单一职责
一个类,应该只做一方面的事情。
反例:
public class Phone {
void call(String number){}
void close(){}
void sendMessage(String number){}
void reciveMessage(){}
}
一个电话,包括打电话,发短信,如果还有聊微信、聊QQ、邮箱,那这个类就是一个大杂烩。
正例:
public class Call {
void call(){}
void close(){}
}
public class Mesage {
void send(){}
void receive(){}
}
public class Phone {
private Call call;
private Mesage mesage;
public Call getCall() {
return call;
}
public void setCall(Call call) {
this.call = call;
}
public Mesage getMesage() {
return mesage;
}
public void setMesage(Mesage mesage) {
this.mesage = mesage;
}
}
Phone是对外接口,这里看起来又违背了开闭原则,不过Call 和 Message实在是抽象不出来了。大概是这个意思就行,Phone看起来没那么杂乱了。至少不都实现,只用Call的只用Call,只用Message的只用Message。
3、里氏替换原则
子类可以扩展父类的功能,但不能修改父类已有的功能。让我想起了模板模式,模板方法不要改。
比如,客户,vip客户,普通客户,而发邮件是vip和普通都一样的。那就客户里面定义好发邮件功能,vip和普通直接拿来用不要修改。修改当然可以,但是通用功能没必要修改。要优雅。
4、依赖倒转原则
没太看明白
5、接口隔离原则
理解为接口分离,接口里面功能尽量少,可以创建多个接口。与单一职责差不多,单一职责是说实现,接口隔离是功能越少越好,灵活。
6、迪米特原则
听起来像是limit,一个类要对其他类知道越少越好,只管引用,不管实现。如果一辆车开动类,包含引发发动机、检测油箱、检测轮胎、开动雨刷,就对其他类知道的太多了。如果修改开动类,增加停车方法,就会修改其他那几项。
这时候如果独立出来一个控制类,增加停车方法,只需要修改增加控制类,不需大改对外的开动类。
二十三
创建型:
1、单例;2工厂方法;3抽象工厂;4创造者;5原型
结构型:
1、适配器;2桥接;3装饰;4组合;5享元;6代理;7外观
行为型:
1、观察;2访问;3中介者;4解释器;5迭代器;6状态;7命令;8策略;9备忘录;10职责链;11模板方法
1、适配器模式:两个不相同的类,集合到一起工作。比如,一个接口FacadeA需要调用ClassB的方法funC(),则设计一个适配器类AdapterAB implement FacadeA extentd ClassB,这样就可以使用super.funC()了,而不是在FacadeA的实现类FacadeAImpl里面调用ClassB对象的funC()方法。
好处就是:想增加多少个适配器就增加多少个。不用修改FacadeAImpl里面的方法,符合开闭原则。
2、装饰器模式:使用ClassB,为ClassA进行功能加强。最典型的应用为:BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(System.in)); IO输入里面有很多装饰器模式的思想,这里的BufferedReader就是InputStreamReader的装饰器,为InputStreamReader新添加了Buffer功能。
3、代理模式:FacadeA有实现类FacadeAImpl,用户可以直接调用FacadeA的实现类方法,但是如果想要在方法之间做点什么,所有的用户们则都需要自己重复造轮子。所以如果有个代理类,承包了在调用FacadeA方法funC()之前和之后的操作,就免去了用户们的额外重复工作。
想对被代理的功能做点额外的事,又不想侵入代码----静态代理为在代码中调用对象方法,这样保证了遵循开闭原则,但是每次有改动的需要(新增接口)还得改动代理类;而动态代理,可以在调用代理类的时候,才指定调用的对象,完全不需要重写代理类,可以用实现Proxy和CGLib的方法。
4、