纯属个人拙见,欢迎指点
物极必反的道理大家都明白,这些原则并不是要我们刻板的去遵守。开发需要遵循实际条件,不能按部就班的来完成一个项目。但这些原则,能帮我们在编码项目过程中,避开不必要的错误,提升项目的可维护性。
设计模式有六大原则,分别是:
- 开闭原则
- 里氏代换原则
- 单一职责原则
- 依赖倒置原则
- 接口隔离原则
- 迪米特法则
开闭原则
对扩展开放,对修改关闭。当软件有新功能,新变化时,我们应该尽可能去增加他的行为方法来改变,而不是通过修改现有代码来满足。这就是为什么,好的软件项目通常具有非常棒的扩展性。
工厂模式就遵守这一原则
编程的总原则是:低耦合,高内聚。
里氏代换原则
子类可以去扩展父类,但请尽量避免重写父类的方法,除非父类是一个基类。因为会出现,当你在子类需要使用父类的一个方法时,而此时这个方法刚好被子类重写,就可能会出现问题。
代码说明:
//父亲喜欢读军事书籍
public class Father{
public void readBook(){
System.out.println("读军事书籍");
}
}
/*儿子除了喜欢读军事书籍外,还喜欢读科幻小说,此时就需要扩展读科幻小说的方法。在这里,当子类重写了父类的方法后,他就无法使用父类的readBook()方法。
*/
public class Son extends Father{
public void readBook(){
System.out.println("读科幻小说");
}
}
//家庭
public class Family{
public static void main(String[] args){
Son son = new Son();
son.readBook();
}
}
输出结果只有:读科幻小说
单一职责原则
好比生活中的各个职业,负责各种的岗位,比如交警,职责上只负责交通管理,他不参与消防等其他工作的道理相同。
代码说明:
public class Person{
//管理交通
public void manageTraffic(){
}
//消防工作
public void controlFire(){
}
//救治病人
public void treatmentPatient(){
}
}
如果我们这样写,来描述不同人的不同职责,那么会发生什么么?
//社会
public class Social{
public static void main(String[] args){
Person person1 = new Person();
//此时person1是交警
person.manageTraffic();
Person person2 = new Person();
//此时person2是消防员
person2.controlFire();
Person person3 = new Person();
//此时person3是医生
person3.controlFire();
}
}
这里Person类里面,不同职业的人,有且我们只用到了属于他的职能,但其他不相关的职能也被放置在里面的话,可能被滥用。
就存在违反单一职责。
遵循这一原则的话,我们需要把不同对象独立出来,例如交警
//这是一个交警类
public class TrafficPolice{
//管理交通
public void manageTraffic(){
System.out.println("管理交通");
}
}
有时候不要为了灵活而取巧,在实际开发中,代码的往往很复杂,遵循这一原则你可以方便的维护你的代码,减少代码的复杂性。
依赖倒置原则
中心思想就是面向接口编程,就是如果类需要依赖对象,而依赖的作用是为了使用该对象的方法,那么我们考虑用依赖接口的来达到这个目的。
相当拗口,举个人穿衣服的例子。
//外套类
public class Coat{
//穿上的类型
public void onType(){
System.out.println("外套穿上");
}
}
//人类
public class Person{
//此处和外套进行了依赖
public void wear(Coat coat){
System.out.println(coat.onType());
}
}
//穿衣
public class WearClothing{
public static void main(String[] args){
Person person = new Person();
person.wear(new Coat());
}
}
结果为:外套穿上
但是,我们穿衣打扮这件事情,不可能只穿外套,而不穿内衣裤、鞋子。
//鞋子类
public class Shose{
//穿上的类型
public void onType(){
System.out.println("鞋子穿上");
}
}
不难看出,当我们需要穿上鞋子时,必须在人这个类里修改代码,你需要再添加鞋子的依赖,否则,我们没法穿上。即改为:
public class Person{
//此处和外套进行了依赖
public void wear(Coat coat){
System.out.println(coat.onType());
}
//此处和鞋子进行了依赖
public void wear(Shose shose){
System.out.println(shose.onType());
}
}
//穿衣
public class WearClothing{
public static void main(String[] args){
Person person = new Person();
person.wear(new Coat());
person.wear(new Shose());
}
}
结果为:外套穿上
鞋子穿上
发现没有,如果当依赖对象的实现越多,Person类修改的也需要越多,但Person这个类是在高层,它负责业务逻辑的处理,应该去依赖抽象(抽象类或借口)来减少这些耦合。
这里的高层指事件的发起处(人),底层指最后的现实处(各种衣物)。
因为都属于衣物,所以我们可以定义一个IClothing的接口。
//穿衣打扮接口
interface IClothing{
public void onType();
}
让底层的Coat、Shoes去具体现实各自的IClothing这个接口。
//外套
public class Coat implements IClothing{
public void onType(){
System.out.println("外套穿上");
}
}
//鞋子类
public class Shose implements IClothing{
public void onType(){
System.out.println("鞋子穿上");
}
}
在Person这个类里,我们依赖接口,而不是底层
public class Person {
public void wear(IClothing iClothing){
System.out.println(iClothing.onType());
}
}
最后,我们发现,只要传入接口的实现,而不需要在高层(Person)里修改代码,就能得到我们要的结果。
public class WearClothing{
public static void main(String[] args){
Person person = new Person();
person.wear(new Coat());
person.wear(new Shose());
}
}
结果为:外套穿上
鞋子穿上
说了这么多,我们要明白的一件事情就是这么做的理由,高层的东西之所以要避免去修改,是因为它是事件逻辑操作入口,一旦修改,极有可能造成程序其他地方用到此高层的地方出错,而依赖抽象可以很好的解决这种耦合。
接口隔离原则
高层应只依赖对它有用的接口
举个人的行为习惯的例子
inteface Action {
//吃
public void eat();
//睡
public void sleep();
//喝
public void drink();
//谈话
public void talk();
//工作
public void work();
//购物
public void shopping();
}
//女人
public class Women{
Action action;
public Women(Action action){
this.action = action;
}
public void hasAction(){
action.eat();
action.sleep();
action.drink();
action.talk();
action.work();
action.shopping();
}
}
public class WomenAction implements Action{
//吃
public void eat(){
System.out.println("吃");
};
//睡
public void sleep(){
System.out.println("睡");
};
//喝
public void drink(){
System.out.println("喝");
};
//谈话
public void talk(){
System.out.println("谈话");
};
//工作
public void work(){
System.out.println("工作");
};
//购物
public void shopping(){
System.out.println("购物");
};
}
public class Baby{
Action action;
public Baby(Action action){
this.action = action;
}
public void hasAction(){
action.eat();
action.sleep();
action.drink();
}
}
//婴儿
public class BabyAction implements Action{
//吃
public void eat(){
System.out.println("吃");
};
//睡
public void sleep(){
System.out.println("睡");
};
//喝
public void drink(){
System.out.println("喝");
};
//婴儿不会谈话,工作,购物,但是由于实现了Action这个接口,它的所有方法都必须被重写
public void talk(){
};
public void work(){
};
public void shopping(){
};
}
public class Behaviour{
public static void main(String[] args){
Women women = new Women(new WomenAction());
women.hasAction();
Baby baby = new Baby(new BabyAction())
baby.hasAction();
}
}
结果为:吃
睡
喝
谈话
工作
购物
吃
睡
喝
看到婴儿的行为习惯实现,类的有几个方法是没被用到的,这就造成了代码的臃肿 ,这时就需要对接口进行拆分隔离,使得WomenAction和BabyAction要实现接口最小。讲Action进行拆分,然后再各自实现需要的接口。
//基础的行为接口
inteface IBaseAction {
//吃
public void eat();
//睡
public void sleep();
//喝
public void drink();
}
//女人的行为接口
inteface IWomenAction{
//谈话
public void talk();
//工作
public void work();
//购物
public void shopping();
}
//女人
public class Women{
IBaseAction iBaseAction;
IWomenAction iWomenAction;
public Women(IBaseAction iBaseAction,IWomenAction iWomenAction;){
this.iBaseAction = iBaseAction;
this.iWomenAction = iWomenAction;
}
public void hasAction(){
iBaseAction.eat();
iBaseAction.sleep();
iBaseAction.drink();
iWomenAction.talk();
iWomenAction.work();
iWomenAction.shopping();
}
}
public class WomenAction implements IBaseAction,IWomenAction{
//吃
public void eat(){
System.out.println("吃");
};
//睡
public void sleep(){
System.out.println("睡");
};
//喝
public void drink(){
System.out.println("喝");
};
//谈话
public void talk(){
System.out.println("谈话");
};
//工作
public void work(){
System.out.println("工作");
};
//购物
public void shopping(){
System.out.println("购物");
};
}
public class Baby{
IBaseAction iBaseAction;
public Baby(IBaseAction iBaseAction){
this.iBaseAction = iBaseAction;
}
public void hasAction(){
iBaseAction.eat();
iBaseAction.sleep();
iBaseAction.drink();
}
}
//婴儿
public class BabyAction implements IBaseAction{
//吃
public void eat(){
System.out.println("吃");
};
//睡
public void sleep(){
System.out.println("睡");
};
//喝
public void drink(){
System.out.println("喝");
};
}
public class Behaviour{
public static void main(String[] args){
Women women = new Women(new WomenAction());
women.hasAction();
Baby baby = new Baby(new BabyAction())
baby.hasAction();
}
}
结果一样
- 接口要小没错,能提高程序的灵活性,但记住灵活的东西,往往需要付出复杂的代价。所以接口小的要控制好。
迪米特法则
对象与对象之间应尽量减少耦合。
就是不要借用别人的地方做本该属于自己的事情。
又称为最少知道原则。
举个例子,小张和小陈是好朋友,小陈总是会邀请小张去吃饭、唱歌、烫头。
//小张
public class Z{
public void sing(){
System.out.println("唱歌");
}
public void eat(){
System.out.println("吃饭");
}
public void perm(){
System.out.println("烫头");
}
}
//小陈
public class C{
public void inviteZ(Z z ){
z.sing();
z.eat();
z.perm();
}
}
//娱乐
public class Entertainment{
public static void main(String[] args){
C c = new C();
c.inviteZ();
}
}
结果为:唱歌
吃饭
烫头
我们看到在小陈这个类里面他调用了过多的小张方法,也就是小张把把自己的方法公开的太多,这样就大大增加了两者的耦合性,也就是小陈过多的知道小张的爱好。
但朋友间也是需要保持一定距离,才会有舒适感。所以,小张应该只暴露一个方法来给小陈,告诉他们之间有哪些娱乐活动。
//小张
public class Z{
//更改为私有
private void sing(){
System.out.println("唱歌");
}
private void eat(){
System.out.println("吃饭");
}
private void perm(){
System.out.println("烫头");
}
//只暴露一个方法给小陈调用
public void entertainmentWithC(){
sing();
eat();
perm();
}
}
//小陈
public class C{
public void inviteZ(Z z ){
z.entertainmentWithC();
}
}