设计模式它是一种代码编程长期发展的经验和解决某种问题的通用的思想,并且中所周知的一套代码方法和理念。也是我们编写程序的基石。我日常写代码就好比建造房子一样,首先我们需要搭建好架子。然后根据这个架子慢慢的将整个大厦建起来。同样的,我们在编写程序的时候,也需要遵循一定的原则和框架,这样我们写出来的程序才更见健壮,开发起来也会更加省时间,提高代码的可读性,拓展性,重用性,灵活性等,减少开发成本。设计模式原则其实就是程序员在编程时应当遵守的原则,也是设计模式的基础,即设计模式为什么要这样设计的原因。
设计模式六大原则:
(一)、单一职责原则
(二)、接口隔离原则
(三)、依赖倒置原则
(四)、里氏替换原则
(五)、开闭原则
(六)、迪米特法则
下面我将用说明+代码的方式,尽量地将6大原则说明白。
一、单一职责原则
对于一个类/接口/方式而言之负责一个职责或职能。比如说A类负责两个不同的职责,职责1和职责2,当职责1发生需求变更而修改时,有可能会造成职责2执行错误,这是后需要将A类拆分为A1和A2两个。这样做的有点:1.降低了类的复杂性。2.提高了类的可读性,因为一个类只负责一个职责,看起来比较有目的性。3.提高系统的可维护性,降低了当需求变更时修改程序带来的风险。但是,如果一位的最求单一职责原则,有时候可能会造成类爆炸的问题,所以使用时需要谨慎的看待这一点,不过,接口和方法必须要遵守这一原则。
应用实例
我们已交通工具为例,每种交通工具的出行方式都有可能不一样,比如飞机是在天上飞的,汽车在公路上跑,轮船在水上航行。所以我们可以用以下方式来实现:
方式1:
public class Test { public static void main(String[] args) { Vehicle vehicle = new Vehicle(); vehicle.run("汽车"); vehicle.run("飞机"); vehicle.run("轮船"); } } class Vehicle { public void run(String vehicle) { System.out.println(vehicle + " 在公路上跑"); } }
//运行结果
汽车 在公路上跑
飞机 在公路上跑
轮船 在公路上跑
方式1中run方法既负责在公路上跑,也负责在天上飞,也可以在水上航行,很显然违反了单一职责原则。解决的方法:将每种出行方式单独做成一个类,每个类中都有各自的运行方式,所以我们引出了方式2
方式2:
public class SingleResponsible2 { public static void main(String[] args) { RoadVehicle roadVehicle = new RoadVehicle(); roadVehicle.run("汽车"); AirVehicle airVehicle = new AirVehicle(); airVehicle.run("飞机"); WaterVehicle waterVehicle = new WaterVehicle(); waterVehicle.run("邮轮"); } } class RoadVehicle{ public void run(String vehicle) { System.out.println(vehicle + " 在公路上跑"); } } class AirVehicle{ public void run(String vehicle) { System.out.println(vehicle + " 在天上飞 "); } } class WaterVehicle{ public void run(String vehicle) { System.out.println(vehicle + " 在水上航行 "); } }
方式2遵循了单一职责原则,每个类的run方法都只负责各自的类型。但是,我们可以看到这样做需要很大的改动,对于客户端也需要改动很大。因此,我们可以考虑第三种方式,改动Vehicle类型。
方式3:
public class SimgleResponsible3 {
public static void main(String[] args) {
Vehicle vehicle = new Vehicle();
vehicle.airRun("飞机");
vehicle.roadRun("汽车");
vehicle.waterRun("邮轮");
}
}
class Vehicle{
public void roadRun(String vehicle) {
System.out.println(vehicle + "在路上跑");
}
public void airRun(String vehicle) {
System.out.println(vehicle + " 在天空中飞");
}
public void waterRun(String vehicle) {
System.out.println(vehicle + " 水上航行 ");
}
}
这种方式原来的类修改的地方比较少,只是在原来的基础上添加的不同的方法。这种方式虽然在类型不遵循单一职责原则,但是在方式是遵循了这个原则的。
二、接口隔离原则
客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上(Clients should not be forced to depend upon interfaces that they don’t use.)。
类间的依赖关系应该建立在最小的接口上(The dependency of one class to another one should depend on the smallest possible interface)。
问题:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。接口I中有op1,op2,op3,op4和op5这5个方法,类B和类D都实现了接口I,但是类A只需要类B的op1,op2和op3这3个方法,类C只需要类D的op1,op4和op5这3个方法。
在没有遵循接口隔离原则,是这样设计的:
public interface Interface1 {
void op1();
void op2();
void op3();
void op4();
void op5();
}
public class A {
private Interface1 interface1;
public A(Interface1 interface1) {
this.interface1 = interface1;
}
public void depend1() {
interface1.op1();
}
public void depend2() {
interface1.op2();
}
public void depend3() {
interface1.op3();
}
}
public class B implements Interface1 {
@Override
public void op1() {
System.out.println("op1");
}
@Override
public void op2() {
System.out.println("op2");
}
@Override
public void op3() {
System.out.println("op3");
}
@Override
public void op4() {
}
@Override
public void op5() {
}
}
public class C {
public C(Interface1 interface1) {
this.interface1 = interface1;
}
private Interface1 interface1;
public void depend1() {
interface1.op1();
}
public void depend4() {
interface1.op4();
}
public void depend5() {
interface1.op5();
}
}
public class D implements Interface1 {
@Override
public void op1() {
System.out.println("op1");
}
@Override
public void op2() {
System.out.println("op2");
}
@Override
public void op3() {
System.out.println("op3");
}
@Override
public void op4() {
System.out.println("op4");
}
@Override
public void op5() {
System.out.println("op5");
}
}
public class Test {
public static void main(String[] args) {
Interface1 b = new B();
Interface1 d = new D();
A a = new A(b);
C c = new C(d);
a.depend1();
a.depend2();
a.depend3();
c.depend1();
c.depend4();
c.depend5();
}
}
从上面的代码中可以看到,A类通过接口1依赖的B类,但是A类只用到了B的1,2和3的方法,4和5是无用的。同样的,C类只用到了D类的1,4和5的方法。这样就违背了接口隔离的原则。那么接下来就使用接口隔离的原则改进上面代码;
分析:A类和C类都使用到了op1,因此我们可以将op1单独抽奖成一个接口1,然后把A类依赖的op2和op3抽象成接口2,C类依赖的op4和op5抽象成接口3,然后B类实现接口1和接口2,D类实现接口1和接口3,A类依赖B类,C类依赖D类,这样就可以将不用的接口隔离开,代码如下:
public interface Interface1 {
void op1();
}
public interface Interface2 {
void op2();
void op3();
}
public interface Interface3 {
void op4();
void op5();
}
public class A {
public void depend1(Interface1 interface1) {
interface1.op1();
}
public void depend2(Interface2 interface2) {
interface2.op2();
}
public void depend3(Interface2 interface2) {
interface2.op3();
}
}
public class B implements Interface1,Interface2 {
@Override
public void op1() {
System.out.println("B 类实现了 Interface1");
}
@Override
public void op2() {
System.out.println("B 类实现了Interface2");
}
@Override
public void op3() {
System.out.println("B 类实现了Interface2");
}
}
public class C {
public void depend1(Interface1 interface1) {
interface1.op1();
}
public void depend4(Interface3 interface3) {
interface3.op4();
}
public void depend5(Interface3 interface3) {
interface3.op5();
}
}
public class D implements Interface1,Interface3 {
@Override
public void op1() {
System.out.println("D 类实现了 Interface1");
}
@Override
public void op4() {
System.out.println("D 类实现了Interface3");
}
@Override
public void op5() {
System.out.println("D 类实现了Interface3");
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
a.depend1(new B());
a.depend2(new B());
a.depend3(new B());
C c = new C();
D d = new D();
c.depend1(d);
c.depend4(d);
c.depend5(d);
}
}
接口隔离使用注意事项:使用过程我们需要注意把控接口 的细粒度,过度的最求接口隔离,会导致接口数量爆炸,系统中接口泛滥,不利于系统的维护。接口也不能太大,违背了接口隔离的原则,灵活性比较差。适度的控制接口的细粒度,不仅让接口变得更加灵活,而且能够降低系统的耦合度等
三、依赖倒置原则
高层模块不应该依赖底层模块,两者都应该依赖抽象,抽象不应依赖具体,具体应该要依赖于抽象,其核心思想就是面向接口编程。
依赖关系传递的三种方式:
1、接口传递;2、构造方法传递;3、setter方式传递
应用案例:
有一天小王的领导要小王对项目中的商品按照价格从高到低排序,小王接到任务后立即开始写代码了,而且很快就写出来:
public class Sort {
public void doSort() {
System.out.println("sort by price");
}
}
public class Item { public void sort() { new Sort().doSort(); } }