首页 > 其他分享 >设计模式的七大原则

设计模式的七大原则

时间:2022-09-29 21:35:45浏览次数:75  
标签:原则 void 七大 System class println 设计模式 public out

设计模式之七大编程原则

  • 单一职责原则
  • 接口隔离原则
  • 依赖倒转原则
  • 里氏替换原则
  • 迪米特法则
  • 合成复用原则

笔记总结来源于B站:B站尚硅谷——Java设计模式

一、单一职责原则

简而言之,在设计程序的过程中确保一个类或者方法只负责一个职责,或者说只执行一个功能的设计原则被称为单一职责原则


看如下代码:

public class Demo01{
    public static void main(String[] args){
        Animal animal = new Animal();
        animal.eat("小猫");
        animal.eat("老鼠");
        animal.eat("鱼"); //我吃我自己!!!?
    }
}


class Animal{
    void eat(String name){
        System.out.println(name+"在吃鱼!");
    }
}
小猫在吃鱼!
老鼠在吃鱼!
鱼在吃鱼!

根据以上代码,虽然写的很蠢但能反应出一个问题,Animal的家住海边,管的比较宽,导致了小猫、老鼠、鱼都是吃鱼。

这样的代码非常非常非常的不合理,鱼怎么能吃自己呢?

1.2 修改思路

Animal实在是太笼统了,因此他的职位也特别的多,我们需要细分下来到小猫、老鼠、鱼的类,继承或者去实现Animal里面的吃方法

这样子小猫的类只管小猫、老鼠的类只管老鼠、鱼的类只管鱼,遵守单一职责原则

public class Demo01{
    public static void main(String[] args){
        Animal animal = new Animal();
        animal.CatEat("小猫");
        animal.MouseEat("老鼠");
        animal.FishEat("鱼");
    }
}


class Animal{
    void CatEat(String name){
        System.out.println(name+"在吃鱼!");
    }

    void MouseEat(String name){
        System.out.println(name+"偷吃大米!");
    }

    void FishEat(String name){
        System.out.println(name+"吃虾米!");
    }
}
小猫在吃鱼!
老鼠偷吃大米!
鱼吃虾米!

二、接口隔离原则

简而言之,对于A类通过一个接口使用B类的时候,B类所实现的接口应该建立在最小接口上


image

根据以上类图编写如下代码:

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

    }
}

interface Interface1{
    void operation1();
    void operation2();
    void operation3();
    void operation4();
    void operation5();
}

//创建A类实现Interface1类
class B implements Interface1{

    @Override
    public void operation1() {
        System.out.println("A operation1");
        
    }

    @Override
    public void operation2() {
        System.out.println("A operation2");
    }

    @Override
    public void operation3() {
        System.out.println("A operation3");
    }

    @Override
    public void operation4() {
        System.out.println("A operation4");
    }

    @Override
    public void operation5() {

        System.out.println("A operation5");
    }
    
}

//创建A类实现B类
class D implements Interface1{

    @Override
    public void operation1() {
        System.out.println("B operation1");
        
    }

    @Override
    public void operation2() {
        System.out.println("B operation2");
    }

    @Override
    public void operation3() {
        System.out.println("B operation3");
    }

    @Override
    public void operation4() {
        System.out.println("B operation4");
    }

    @Override
    public void operation5() {

        System.out.println("B operation5");
    }
    
}

class A{

    void function1(Interface1 b){
        b.operation1();
    }

    void function2(Interface1 b){
        b.operation2();
    }

    void function3(Interface1 b){
        b.operation3();
    }
}


class C{

    void function1(Interface1 d){
        d.operation1();
    }

    void function4(Interface1 d){
        d.operation4();
    }

    void function5(Interface1 d){
        d.operation5();
    }
}

我是个懒人,这一看就能看出问题,A类只用到了B类的三个方法,C类也只用到了D类的三个方法,但是BD两个类却把接口Interface的所有方法都实现了,代码有点过于臃肿

2.1修改思路

把原来的接口拆开来,拆成多个接口,类只需要去实现他会用到的方法接口就行了,在最小程度上实现接口隔离原则

image

修改代码如下

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

    }
}

interface Interface1{
    void operation1();
}

interface Interface2{

    void operation2();
    void operation3();

}

interface Interface3{
    void operation4();
    void operation5();
}


class B implements Interface1,Interface2{

    @Override
    public void operation1() {
        System.out.println("A operation1");
        
    }

    @Override
    public void operation2() {
        System.out.println("A operation2");
    }

    @Override
    public void operation3() {
        System.out.println("A operation3");
    }
    
}


class D implements Interface1,Interface3{

    @Override
    public void operation1() {
        System.out.println("B operation1");
        
    }

    @Override
    public void operation4() {
        System.out.println("B operation4");
    }

    @Override
    public void operation5() {

        System.out.println("B operation5");
    }
    
}

class A{

    void function1(Interface1 b){
        b.operation1();
    }

    void function2(Interface2 b){
        b.operation2();
    }

    void function3(Interface2 b){
        b.operation3();
    }
}


class C{

    void function1(Interface1 d){
        d.operation1();
    }

    void function4(Interface3 d){
        d.operation4();
    }

    void function5(Interface3 d){
        d.operation5();
    }
}

三、依赖倒转原则

简而言之,在接收具体实现过程时应该交给实现类来完成,但传入参数可以用抽象类和接口来定义,从而设计在调用和传入中间过度一个缓冲层,给代码增加啊伸缩性以及可扩展性


不多bb看代码:

public class Demo03 {
    public static void main(String[] args) {
        Person person = new Person();
        person.receive(new Email());
    }
}

class Email{
    String getInfo(){
        return "Hello, Email";
    }
}

class Person{

    void receive(Email msg){
        System.out.println(msg.getInfo());
    }
}

在这段通俗易懂的代码中,可以看到Person可以接收email的消息,但问题是现在都是2022年了,我想来一个接收飞鸽传书的方式,是不是得在重写一个方法,而且在传入参数直接传入了一个对象,这不是一个很好的选择(虽然我以前经常这么干)

3.1解决思路

根据上述问题,通过依赖倒转原则可以轻松得解决,甚至还很舒服,我看完只能说“66666666666666666666”

第一步我先创建一个Receiver的接口,我不管你是Email、微信、QQ、飞鸽传书哪怕是漂流瓶都得实现这个接口,然后在Person类里面的receive方法的参数msg类型改为Receiver,这样做的好处是:

  • 我可以传递任何实现接口Receiver的类
  • 如果我想增加一个facebook的消息只需要在写一个类去实现Receiver即可
  • 我觉得很有逼格
public class Demo03 {
    public static void main(String[] args) {
        Person person = new Person();
        person.receive(new Email());
        person.receive(new FlyingPigeon());
        person.receive(new QQ());
    }
}

interface Receiver{
    String getInfo();
}

class Email implements Receiver{
    public String getInfo(){
        return "Hello, Email";
    }
}

class FlyingPigeon implements Receiver{
    public String getInfo(){
        return "Hello, I'm good boy";
    }
}

class QQ implements Receiver{
    public String getInfo(){
        return "Hello, You are my friend.";
    }
}

class Person{

    void receive(Receiver msg){
        System.out.println(msg.getInfo());
    }
}

Hello, Email
Hello, I'm good boy
Hello, You are my friend.

四、里氏替换原则

简而言之,子类尽量少重写父类的方法,一定要写可以通过聚合、组合、依赖来解决


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

        B b = new B();

        //在这里我以为我通过B类对象能够调用到A类的fun1
        System.out.println("11-3="+b.fun1(11, 3));
        System.out.println("1-8="+b.fun1(1, 8));
    }
}


class A{
    public int fun1(int a,int b){
        return a-b;
    }
}

class B extends A{

    //试图重载A类方法 但我不知道重载了
    public int fun1(int a,int b){
        return a+b;
    }

    public int fun2(int a,int b){
        return fun1(a,b)+9;
    }
}

在这段代码中有一个逻辑性的错误,在主方法中本意是通过B类对象去调用A类方法,但在B类中错误的将fun1的方法重写了,导致代码上的逻辑性错误,这一错误看似是一个很刻意的,但在实际开发中,很难会提示到自己从写了父类的方法然后在主函数中又错误的调用。

4.1解决思路

在视频课里面,这个例子举得多少有点牵强,并且创造了一个base类,让AB类去继承,但在一个没有更加基础属性和方法的情况下base类是可以不加的,直接在B类中调用A类的方法通过组合来解决这个问题(个人理解),如果后续还要增加一个两个类公共的东西可以创建base类

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

        B b = new B();
      
        System.out.println("11-3="+b.fun3(11, 3));
        System.out.println("1-8="+b.fun3(1, 8));
    }
}


class A{
    public int fun1(int a,int b){
        return a-b;
    }
}

class B{

    private A a = new A();

    public int fun1(int a,int b){
        return a+b;
    }

    public int fun2(int a,int b){
        return fun1(a,b)+9;
    }

    public int fun3(int a,int b){
        return this.a.fun1(a, b);
    }
}

五、开闭原则

对扩展功能开放,对修改功能关闭

public class Demo05 {
    public static void main(String[] args) {
        GraphicEditor graphicEditor = new GraphicEditor();

        graphicEditor.drawShape(new Circle());
        graphicEditor.drawShape(new Rectangle());
    }
}


class GraphicEditor{

    public void drawShape(Shape s){
        if(s.m_type == 1){
            this.drawRect(s);
        }else if(s.m_type == 2){
            this.drawCircle(s);
        }
    }

    public void drawRect(Shape r){
        System.out.println("矩形");
    }

    public void drawCircle(Shape r){
        System.out.println("圆");
    }
}

class Shape{
    int m_type;
}

class Rectangle extends Shape{
    Rectangle(){
        super.m_type = 1;
    }
}

class Circle extends Shape{
    Circle(){
        super.m_type = 2;
    }
}

就不输出了,在上述代码中创建了一个画图形的类(GraphicEditor),里面有一个方法drawShape,根据传递进去的s的m_type来判断到底是画矩形还是画圆,如果我现在想增加一个画三角形的代码需要更改几处地方???

5.1解决思路

其实就是想打算在不修改GraphicEditor的情况下增加功能,这样我就可以对使用方关闭修改,在另外一处开辟一个拓展的功能,这里用到的跟依赖倒转原则很像,创建一个抽象类作为缓冲层,对外扩展可以新增实现这个抽象类的实现类

public class Demo05 {
    public static void main(String[] args) {
        GraphicEditor graphicEditor = new GraphicEditor();

        graphicEditor.drawShape(new Circle());
        graphicEditor.drawShape(new Rectangle());
    }
}

class GraphicEditor{

    public void drawShape(Shape s){
        s.draw();
    }

}

abstract class Shape{
    int m_type;

    abstract void draw();
}

class Rectangle extends Shape{
    Rectangle(){
        super.m_type = 1;
    }

    @Override
    void draw() {
        System.out.println("矩形");
    }

    
}

class Circle extends Shape{
    Circle(){
        super.m_type = 2;
    }

    @Override
    void draw() {
        System.out.println("圆");
    }

    
}

六、迪米特法则

也叫最少知道法则,陌生的类尽量不要以局部变量的形式出现,对依赖的类知道的越少越好

迪米特法则

七、合成复用原则

能用合成/聚合就不用继承

合成复用原则

标签:原则,void,七大,System,class,println,设计模式,public,out
From: https://www.cnblogs.com/Star-Vik/p/16743121.html

相关文章

  • 【设计模式】29.结构型模式-装饰模式(Decorator)
    一、描述装饰模式能够在不改变原来对象结构和功能的前提下,动态的给对象增加新的功能,相比于使用子类扩展的方式,装饰模式更加的灵活。角色(1)抽象构件类:为具体构件类和装饰......
  • 行为型设计模式之观察者模式
    观察者模式观察者模式,又叫发布-订阅模式,它属于行为型模式。它是定义一种一对多的依赖关系,一个主题对象可被多个观察者对象同时监听,使得每当主题对象状态变化时,所有依赖于......
  • 对《Head First设计模式》的更多赞誉
    ​​软件方法(下)分析和设计第8章连载[20210723更新]>>​​​​ErichGamma:我把它带到健身房-对《HeadFirst设计模式》的赞誉​​​​技术书籍也香艳-《HeadFirst设计模式》......
  • 设计模式之模板方法模式
    在我们实际开发中,如果一个方法极其复杂时,如果我们将所有的逻辑写在一个方法中,那维护起来就很困难,要替换某些步骤时都要重新写,这样代码的扩展性就很差,当遇到这种情况就要考......
  • 初识设计模式 - 装饰器模式
    简介装饰器模式主要解决的问题是,如果使用子类继承的方式扩展一个类,随着扩展功能的增多,子类会非常膨胀,包括子类的数量或子类的方法数。装饰器模式其核心还是“用组合替代......
  • 大话设计模式--------第二章策略模式
    第二章策略模式策略模式的概念很好理解,它将对象和行为分开,将行为定义为一个行为接口和具体行为的实现,每个if判断都可以理解为一个策略。比如商场有三种客户,第一种打8折,......
  • 行为型设计模式之中介者模式
    中介者模式中介者模式又称为调解者模式或调停者模式,属于行为型模式。它用一个中介对象封装系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独......
  • 行为型设计模式之备忘录模式
    备忘录模式备忘录模式又称为快照模式或令牌模式,属于行为型模式。它是指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可将该对象......
  • 设计模式 -- Singleton(单例模式)
    单例模式(Singleton)保证一个类仅有一个实例,并提供一个该实例的全局访问点。在软件系统中,经常有这样一个特殊的类,必须保证它们在系统中只存在一个示例,才能确保他们的逻辑......
  • 设计模式 -- Flyweight(享元模式)
    享元模式(Flyweight)运用共享技术有效地支持大量的细粒度对象在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行是代价——主......