尚硅谷设计模式学习---[设计模式七大原则]

Posted 小智RE0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了尚硅谷设计模式学习---[设计模式七大原则]相关的知识,希望对你有一定的参考价值。

尚硅谷传送门==>B站尚硅谷Java设计模式

❤❤❤感谢尚硅谷❤❤❤

最近开始计划学习一下设计模式了,加油!!!



设计模式就是对软件设计中普遍存在(反复出现)的问题,提出的解决方案.

面向对象 = =>功能模块[设计模式+算法(数据结构)]
= =>框架[使用到多种设计模式]= = >架构 [服务器集群]

设计模式的目的是为了 提高代码的可重用性 (相同功能的代码提取出来), 可读性 (编写程序时规范书写),可扩展性 (方便扩展增加新功能), 可靠性 (增加新功能后不影响原来的代码),使得程序高内聚,低耦合.

七大原则是指==> 单一职责原则; 接口隔离原则 ;依赖倒置原则;里氏替换原则 ;开闭原则 ;迪米特原则;合成复用原则.

尽量针对接口编程


1.单一职责原则( Single Responsibility Principle)

通俗地说就是, 一个类就管理一件事, 职责单一;

比如说一个实体类User,它就只负责用户的属性和方法.

或者说在一个类中;每个方法仅负责自己的功能;各司其职;

降低了类的复杂性;提高了可读性

案例:比如说有个交通工具类Transport

/**
 * @Date: 2021/09/21/12:13
 * 单一职责原则学习
 */
public class SingleResponsibility01 {
    public static void main(String[] args) {
        Transport transport = new Transport();
        transport.run("小汽车");
        transport.run("轮船");
        transport.run("飞机");
    }
}

//交通工具类
class   Transport{
    public void run(String transport){
        System.out.println(transport+"正在路上跑");
    }
}

诶,运行后发现;明显不符合逻辑啊;违反了单一职责的原则.

小汽车正在路上跑
轮船正在路上跑
飞机正在路上跑

OK,接下来对它进行修改;
方式1;把交通工具这个类分解开;分成 路上跑的; 天上飞的; 水里游的 交通工具;

/**
 * @Date: 2021/09/21/12:28
 * 单一职责原则学习
 */
public class SingleResponsibility02 {
    public static void main(String[] args) {
        RoundTransport roundTransport = new RoundTransport();
        roundTransport.run("小汽车");

        SkyTransport skyTransport = new SkyTransport();
        skyTransport.run("飞机");

        SwimTransport swimTransport = new SwimTransport();
        swimTransport.run("轮船");
    }
}

//将原来的交通工具类分类;分为3个类;

//路上跑的交通工具类;
class RoundTransport{
    public void run(String roundTransport){
        System.out.println(roundTransport+"在路上跑");
    }
}
//在天上飞的工具;
class SkyTransport{
    public void run(String skyTransport){
        System.out.println(skyTransport+"在天上飞");
    }
}
//在水里游的工具;
class SwimTransport{
    public void run(String swimTransport){
        System.out.println(swimTransport+"在水里游");
    }
}

诶,每个类负责一种交通工具;

小汽车在路上跑
飞机在天上飞
轮船在水里游

虽然说遵守了单一职责原则,但是将原先的类分解,同时修改了客户端;

方式2;直接在交通工具类中扩展不同的方法;分别负责不同的功能;

public class SingleResponsibility03 {
    public static void main(String[] args) {
        Transport transport = new Transport();
        transport.runRond("小汽车");
        transport.runSwim("轮船");
        transport.runSky("飞机");
    }
}

//交通工具类
class   Transport{
    //路上跑的交通工具执行方法;
    public void runRond(String transport){
        System.out.println(transport+"正在路上跑");
    }
    //天上飞的交通工具执行方法;
    public void runSky(String transport){
        System.out.println(transport+"正在天上飞");
    }
    //水里游的交通工具执行方法;
    public void runSwim(String transport){
        System.out.println(transport+"正在水里游");
    }
}

每个方法负责实现一种功能;在方法上,遵守了单一职责原则

小汽车正在路上跑
轮船正在水里游
飞机正在天上飞

2.接口隔离原则(Interface Segregation Principle)

比如说,一个接口有许多方法,但是类 A 需要的功能只有几个方法,那么就需要把原来的接口拆分一下,让类A去通过他需要的接口去使用方法.

案例;
一个接口有5个方法;类B和类D实现接口;
而类A依赖类B后,仅使用方法1,方法2,方法3;
而类C依赖类D后;仅使用方法1,方法4,方法5;

package com.lzq.principle.interfacesegregation;

public class InterfaceSegregation01 {
    public static void main(String[] args) {

    }
}

//接口'
interface Interface1{
    void method1();
    void method2();
    void method3();
    void method4();
    void method5();
}

//类 B 实现接口;
class B implements Interface1{
    public void method1() {
        System.out.println("类B实现接口的方法1 ");
    }

    public void method2() {
        System.out.println("类B实现接口的方法2 ");
    }

    public void method3() {
        System.out.println("类B实现接口的方法3 ");
    }

    public void method4() {
        System.out.println("类B实现接口的方法4 ");
    }

    public void method5() {
        System.out.println("类B实现接口的方法5 ");
    }
}

//类 D 实现接口;
class D implements Interface1{
    public void method1() {
        System.out.println("类D实现接口的方法1 ");
    }

    public void method2() {
        System.out.println("类D实现接口的方法2 ");
    }

    public void method3() {
        System.out.println("类D实现接口的方法3 ");
    }

    public void method4() {
        System.out.println("类D实现接口的方法4 ");
    }

    public void method5() {
        System.out.println("类D实现接口的方法5 ");
    }
}

//类  A 通过参数接口 依赖 类B ; 仅需要方法1,方法2,方法3;
class A{
    public  void depend1(Interface1 interface1){
        interface1.method1();
    }
    public  void depend2(Interface1 interface1){
        interface1.method2();
    }
    public  void depend3(Interface1 interface1){
        interface1.method3();
    }
}

//类 C 通过参数接口 依赖 类D ,仅需要方法1,方法4,方法5;
class C{
    public  void depend1(Interface1 interface1){
        interface1.method1();
    }
    public  void depend4(Interface1 interface1){
        interface1.method4();
    }
    public  void depend5(Interface1 interface1){
        interface1.method5();
    }
}

但是,按着这样分配的话,那么类C没必要去写方法4和方法5;类D没有必要去写方法2和方法3;

优化

将接口拆分为3个接口;
一个接口放置方法1;
一个接口放置方法2和方法3;
一个接口放置方法4和方法5.

package com.lzq.principle.interfacesegregation;

/**
 * @Date: 2021/09/21/13:00
 */
public class InterfaceSegregation02 {
    public static void main(String[] args) {
        //类A通过接口去使用类B;
        A a=new A();
        a.depend1(new B());
        a.depend2(new B());
        a.depend3(new B());
        //类C通过接口去使用类D;
        C c=new C();
        c.depend1(new D());
        c.depend4(new D());
        c.depend5(new D());
    }
}

//接口'
interface Interface1{
    void method1();
}
//接口拆分出的接口2;
interface Interface2{
    void method2();
    void method3();
}

//接口拆分出的接口3;
interface Interface3{
    void method4();
    void method5();
}

//类 B 实现接口;
class B implements Interface1,Interface2{
    public void method1() {
        System.out.println("类B实现接口1的方法1 ");
    }

    public void method2() {
        System.out.println("类B实现接口2的方法2 ");
    }

    public void method3() {
        System.out.println("类B实现接口2的方法3 ");
    }
}

//类 D 实现接口;
class D implements Interface1,Interface3{
    public void method1() {
        System.out.println("类D实现接口1的方法1 ");
    }

    public void method4() {
        System.out.println("类D实现接口3的方法4 ");
    }

    public void method5() {
        System.out.println("类D实现接口3的方法5 ");
    }
}

//类  A 通过参数接口 依赖 类B ; 仅需要方法1,方法2,方法3;
class A{
    public  void depend1(Interface1 interface1){
        interface1.method1();
    }
    public  void depend2(Interface2 interface2){
        interface2.method2();
    }
    public  void depend3(Interface2 interface2){
        interface2.method3();
    }
}

//类 C 通过参数接口 依赖 类D ,仅需要方法1,方法4,方法5;
class C{
    public  void depend1(Interface1 interface1){
        interface1.method1();
    }
    public  void depend4(Interface3 interface3){
        interface3.method4();
    }
    public  void depend5(Interface3 interface3){
        interface3.method5();
    }
}

输出

B实现接口1的方法1B实现接口2的方法2B实现接口2的方法3D实现接口1的方法1D实现接口3的方法4D实现接口3的方法5 

3.依赖倒置原则(Dependence Inversion Principle)

核心就是面向接口编程;
让细节的具体实现类去依赖(使用)抽象类或者接口;而不是让接口或抽象类去依赖细节的具体实现类.

案例;

不用依赖倒置原则的案例;
比如说,有一个短信类,一个QQ消息类;
在用户Person类中需要不同的方法接受不同的消息.

public class DependenceInversion01 {
    public static void main(String[] args) {
        Person person=new Person();
        person.getMes(new QQ());
        person.getMes(new Message());
    }
}

//短信类;
class Message{
    public String show(){
       return "收到短信了";
    }
}

//QQ消息;
class QQ{
    public String show(){
       return "收到QQ消息了";
    }
}

//具体的人;
class Person{
    //接收短信;
    public void getMes(Message message){
        System.out.println(message.show());
    }
    //接收QQ消息;
    public void getMes(QQ qq){
        System.out.println(qq.show());
    }
}

虽然输出没什么问题;但是一旦又需要接受电子邮件信息呢,接受电话呢…;又要在Person类中重新写方法吗?

收到QQ消息了
收到短信了

根据依赖倒置原则进行案例优化

将接受消息的方法提取;变为接口GetMes;
这样,即使需要接受别的消息,也不用在Person类中再去增加方法;

public class DependenceInversion02 {
    public static void main(String[] args) {
        Person person=new Person();
        person.getMes(new QQ());
        person.getMes(new Message());
    }
}

//接收消息的接口;
interface GetMes{
    //看看收到的消息;
    String show();
}

//短信类;
class Message implements GetMes{
    public String show(){
       return "收到短信了";
    }
}

//QQ消息;
class QQ implements GetMes{
    public String show(){
       return "收到QQ消息了";
    }
}

//具体的人;
class Person{
    //接收消息;
    public void getMes(GetMes getMes){
        System.out.println(getMes.show());
    }
}

关于依赖倒置原则中的依赖关系传递三种方式;
接口传递 ;构造方法传递 ;setter方法传递


4.里氏替换原则(Liskov Substitution Principle)

在面向对象编程语言的继承关系中,父类已经实现的方法,若子类进行修改,可能会产生问题.

使用继承虽然是比较方便的,但是会出现入侵,程序的可移植性降低,程序间的耦合性过高.

根据里氏替换原则,子类中尽量不要重写父类的方法;
所有引用父类的位置,要做到可以透明地使用子类的对象.
如果说子类还是需要父类的方法,可采用聚合,组合,依赖的方式.


案例;类 B 继承了类 A后,没有注意到已经重写了类A的方法 func1();
而且在重写的方法内修改了具体实现.

public class LiskovSubstitution01 {
    public static void main(String[] args) {
        System.out.println("类A调用方法");
        A a = new A();
        System.out.println("11-3=" + a.func1(11, 3));
        System.out.println("1-8=" + a.func1(1, 8));
        System.out.println("类B调用方法");
        B b = new B();
        System.out.println("11-3=" + b.func1(11, 3));
        System.out.println("1-8=" + b.func1(1, 8));
        System.out.println("11+3+9=" + b.func2(11, 3));
    }
}

//类 A 完成两数相减的任务;
class A {
    public int func1(int num1, int num2) 尚硅谷设计模式学习(16)---[访问者模式(Visitor Pattern)]

尚硅谷设计模式学习---[单例模式]

尚硅谷设计模式学习---[UML类图]

尚硅谷设计模式学习---[装饰者模式]

尚硅谷设计模式学习---[桥接模式(Bridge)]

尚硅谷设计模式学习(23)---[策略模式(strategy pattern)]