设计模式
课程链接: bilibili尚硅谷课程
- 设计模式的七大原则
- 单一职责原则
- 接口分离原则
- 依赖反转原则
- 里氏替换原则
- 开闭原则
- 迪米特法则
- 合成复用原则
1 单一职责原则
顾名思义:一个类只应该对一项负责
public class Singleresponsibility {
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 + " 在公路上跑");
}
}
上述代码Vehicle类一个类承担了所有交通工具run的功能,并不是合理的设计,需要对其进行分离。
public class Singleresponsibility2 {
public static void main(String[] args) {
RoadVehicle roadVehicle = new RoadVehicle();
roadVehicle.run("摩托车");
roadVehicle.run("汽车");
WaterVehicle waterVehicle = new WaterVehicle();
waterVehicle.run("船");
AirVehicle airVehicle = new AirVehicle();
airVehicle.run("飞机");
}
}
class AirVehicle {
public void run(String vehicle) {
System.out.println(vehicle + " 在天空运行");
}
}
class RoadVehicle {
public void run(String vehicle) {
System.out.println(vehicle + "在路上运行");
}
}
class WaterVehicle {
public void run(String vehicle){
System.out.println(vehicle + "在水中运行");
}
}
上述代码做到了单一原则,一个类负责各自的领域,但是改动太大了
public class Singleresponsibility3 {
public static void main(String[] args) {
Vehicle2 vehicle2 = new Vehicle2();
vehicle2.run("汽车");
vehicle2.runWater("轮船");
vehicle2.runAir("飞机");
}
}
// 方式3的分析
// 1. 未对原来的类做大的修改,只是增加方法
// 2. 在类的级别上未遵守单一职责,但在方法的级别上遵守了单一职责
class Vehicle2 {
public void run(String vehicle){
System.out.println(vehicle + " 在公路上运行");
}
public void runAir(String vehicle){
System.out.println(vehicle + " 在天空中运行");
}
public void runWater(String vehicle){
System.out.println(vehicle + " 在水中运行");
}
}
老师介绍了上面三种改进的方法,如果让我设计会设计成如下方案:
public class Singleresponsibility4 {
public static void main(String[] args) {
VehcileWays vehcileWays = new VehcileWays();
vehcileWays.show(new Car());
vehcileWays.show(new Plane());
vehcileWays.show(new Boat());
}
}
interface Vehicles{
void run();
}
class Car implements Vehicles{
private String name;
@Override
public void run() {
System.out.println("汽车在公路上运行");
}
}
class Boat implements Vehicles{
@Override
public void run() {
System.out.println("船在水上运行");
}
}
class Plane implements Vehicles{
@Override
public void run() {
System.out.println("飞机在空中运行");
}
}
class VehcileWays{
public void show(Vehicles vehicles){
vehicles.run();
}
}
命名方式有待商榷
2 接口隔离原则
让接口负责的内容尽可能小,大接口拆分为小接口,避免接口浪费
-
原来的大接口模式
package com.qxd.principle; public class Segregation { public static void main(String[] args) { } } interface Interface1{ void operation1(); void operation2(); void operation3(); void operation4(); void operation5(); } class B implements Interface1 { public void operation1() { System.out.println("B 实现了 operation1"); } public void operation2() { System.out.println("B 实现了 operation2"); } public void operation3() { System.out.println("B 实现了 operation3"); } public void operation4() { System.out.println("B 实现了 operation4"); } public void operation5() { System.out.println("B 实现了 operation5"); } } class D implements Interface1 { public void operation1() { System.out.println("D 实现了 operation1"); } public void operation2() { System.out.println("D 实现了 operation2"); } public void operation3() { System.out.println("D 实现了 operation3"); } public void operation4() { System.out.println("D 实现了 operation4"); } public void operation5() { System.out.println("D 实现了 operation5"); } } class A { //A 类通过接口 Interface1 依赖(使用) B 类,但是只会用到 1,2,3 方法 public void depend1(Interface1 i) { i.operation1(); } public void depend2(Interface1 i) { i.operation2(); } public void depend3(Interface1 i) { i.operation3(); } } class C { //C 类通过接口 Interface1 依赖(使用) D 类,但是只会用到 1,4,5 方法 public void depend1(Interface1 i) { i.operation1(); } public void depend4(Interface1 i) { i.operation4(); } public void depend5(Interface1 i) { i.operation5(); } }
class A 与class B通过接口Interface1发生关系,Interface1就是缓冲层,避免两者发生直接的碰撞,A只要调用B的1,2,3方法,但是B实现了接口的所有方法,说明这个接口太大了,需要瘦身。
package com.qxd.principle.improve; public class Segregation1 { public static void main(String[] args) { A a = new A(); a.depend1(new B()); // A 类通过接口去依赖 B 类 a.depend2(new B()); a.depend3(new B()); C c = new C(); c.depend1(new D()); // C 类通过接口去依赖(使用)D 类 c.depend4(new D()); c.depend5(new D()); } } // 接 口 1 interface Interface1 { void operation1(); } // 接 口 2 interface Interface2 { void operation2(); void operation3(); } // 接 口 3 interface Interface3 { void operation4(); void operation5(); } class B implements Interface1, Interface2 { public void operation1() { System.out.println("B 实现了 operation1"); } public void operation2() { System.out.println("B 实现了 operation2"); } public void operation3() { System.out.println("B 实现了 operation3"); } } class D implements Interface1, Interface3 { public void operation1() { System.out.println("D 实现了 operation1"); } public void operation4() { System.out.println("D 实现了 operation4"); } public void operation5() { System.out.println("D 实现了 operation5"); } } class A { // A 类通过接口 Interface1,Interface2 依赖(使用) B 类,但是只会用到 1,2,3 方法 public void depend1(Interface1 i) { i.operation1(); } public void depend2(Interface2 i) { i.operation2(); } public void depend3(Interface2 i) { i.operation3(); } } class C { // C 类通过接口 Interface1,Interface3 依赖(使用) D 类,但是只会用到 1,4,5 方法 public void depend1(Interface1 i) { i.operation1(); } public void depend4(Interface3 i) { i.operation4(); } public void depend5(Interface3 i) { i.operation5(); } }
接口的设计也需要“求同存异”
3 依赖倒转原则
本质就是面向接口编程
比如 class A中的某个方法形参为class B ,那么以后传入的参数就只能是class B了, 拓展性差。
但是class A中某个方法形参为class B抽象的接口的话,那么传入的参数就是该接口的实现类,易于维护。
package com.qxd.principle.inversion;
public class DependyInversion{
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
}
}
class Email {
public String getInfo() {
return "电子邮件信息: hello,world";
}
}
class Person {
public void receive(Email email ) {
System.out.println(email.getInfo());
}
}
*****************************************************************************************************
public class DependyInversion{
public static void main(String[] args) {
//客户端无需改变
Person person = new Person();
person.receive(new Email());
person.receive(new WeiXin());
}
}
//定义接口
interface IReceiver {
public String getInfo();
}
class Email implements IReceiver{
public String getInfo() {
return "电子邮件信息: hello,world";
}
}
//增加微信
class WeiXin implements IReceiver {
public String getInfo() {
return "微信信息: hello,ok";
}
}
class Person {
public void receive(IReceiver iReceiver ) {
System.out.println(iReceiver.getInfo());
}
}
上述两端代码对比即可发现两者的差距
-
依赖关系传递的三种方式和应用案例
- 接口传递
//打开或者关闭哪个电视 interface IOpenAndClose { public void open(ITV tv); //抽象方法,接收接口 } interface ITV { //ITV 接口 public void play(); } // 实现接口 class OpenAndClose implements IOpenAndClose{ public void open(ITV tv){ tv.play(); } }
- 构造方法传递应用案例代码
class OpenAndClose2 { public ITV tv; //成员 public OpenAndClose2(ITV tv) { //构造器 this.tv = tv; } public void open() { this.tv.play(); } }
-
setter 方式传递
上述代码构造器传值改为set传值