乐趣区

关于spring:设计模式学习03Java实现软件设计6大原则

写在后面

  • 记录学习设计模式的笔记
  • 进步对设计模式的灵活运用

学习地址

https://www.bilibili.com/vide…

https://www.bilibili.com/vide…

参考文章

http://c.biancheng.net/view/1…

我的项目源码
https://gitee.com/zhuang-kang/DesignPattern

3,软件设计准则

在软件开发中,为了进步软件系统的可维护性和可复用性,减少软件的可扩展性和灵活性,程序员要尽量依据 6 条准则来开发程序,从而进步软件开发效率、节约软件开发老本和保护老本。

3.1 开闭准则

对扩大凋谢,对批改敞开 。在程序须要进行拓展的时候,不能去批改原有的代码,实现一个热插拔的成果。简言之,是为了使程序的扩展性好,易于保护和降级。

想要达到这样的成果,咱们须要应用接口和抽象类。

因为形象灵活性好,适应性广,只有形象的正当,能够根本放弃软件架构的稳固。而软件中易变的细节能够从抽象派生来的实现类来进行扩大,当软件须要发生变化时,只须要依据需要从新派生一个实现类来扩大就能够了。

3.2 里氏代换准则

里氏代换准则是面向对象设计的根本准则之一。

里氏代换准则:任何基类能够呈现的中央,子类肯定能够呈现。艰深了解:子类能够扩大父类的性能,但不能扭转父类原有的性能。换句话说,子类继承父类时,除增加新的办法实现新增性能外,尽量不要重写父类的办法。

如果通过重写父类的办法来实现新的性能,这样写起来尽管简略,然而整个继承体系的可复用性会比拟差,特地是使用多态比拟频繁时,程序运行出错的概率会十分大。

里氏代换准则谬误示范

package com.zhuang.principle.liskov;

/**
 * @Classname Liskov
 * @Description 里氏代换准则谬误示范
 * @Date 2021/3/15 13:58
 * @Created by dell
 */

public class Liskov {public static void main(String[] args) {A a = new A();
        System.out.println("11-3=" +a.fun1(11,3));
        System.out.println("11-8=" +a.fun1(11,8));

        System.out.println("===================");

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

class A{
    // 返回两个数的差
    public int fun1(int num1,int num2){return num1-num2;}
}

// B 类继承 A 减少新性能,实现两个数相加,而后和 9 求和
class B extends A{
    @Override
    public int fun1(int a, int b) {return a+b;}

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

里氏代换准则正确示范

package com.zhuang.principle.liskov;

/**
 * @Classname Liskov2
 * @Description 里氏代换准则
 * @Date 2021/3/15 14:13
 * @Created by dell
 */

public class Liskov2 {public static void main(String[] args) {Base base = new Base();
        base.add(5,6);
        base.sub(6,2);

        Sub sub = new Sub();
        sub.mul(5,6);
        sub.div(10,2);
    }
}

class Base {
    // 通用加法运算
    public void add(int a, int b) {System.out.println(a + "+" + b + "=" + (a + b));
    }

    // 通用减法运算
    public void sub(int a, int b) {System.out.println(a + "-" + b + "=" + (a - b));
    }
}

class Sub extends Base {
    // 子类特有乘法运算
    public void mul(int a, int b) {System.out.println(a + "*" + b + "=" + (a * b));
    }

    // 子类特有除法运算
    public void div(int a, int b) {System.out.println(a + "/" + b + "=" + (a / b));
    }
}

3.3 依赖倒转准则

高层模块不应该依赖低层模块,两者都应该依赖其形象;形象不应该依赖细节,细节应该依赖形象。简略的说就是要求对形象进行编程,不要对实现进行编程,这样就升高了客户与实现模块间的耦合。

依赖倒转准则谬误示范

package com.zhuang.principle.inversion;



/**
 * @Classname DependenceInversion1
 * @Description 依赖倒转准则谬误示范
 * @Date 2021/3/15 13:20
 * @Created by dell
 */

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

// 定义接口
interface IReceiver{public String getInfo();
}

class WeiXin implements IReceiver{
    @Override
    public String getInfo() {return "发送微信音讯...";}
}
class Email implements IReceiver{
    @Override
    public String getInfo() {return "发送邮件音讯...";}
}
// 对接口的依赖
class Person{public void receive(IReceiver receiver){System.out.println(receiver.getInfo());
    }
}

依赖倒转准则正确示范

package com.zhuang.principle.inversion;

/**
 * @Classname DependenceInversion2
 * @Description 依赖倒转准则正确示范
 * @Date 2021/3/15 13:27
 * @Created by dell
 */

public class DependenceInversion2 {public static void main(String[] args) {Client client = new Client();
        client.receive(new Emailiml());
        client.receive(new WXimpl());
    }
}

interface IReceive{public void printInfo(Integer uid);
}

class WXimpl implements IReceive {
    @Override
    public void printInfo(Integer uid) {System.out.println("发送微信音讯"+uid);
    }
}

class Emailiml implements IReceive {
    @Override
    public void printInfo(Integer uid) {System.out.println("发送邮件信息"+uid);
    }
}
class Client{public void receive(IReceive receive){receive.printInfo(12345);
    }
}

面向对象的开发很好的解决了这个问题,个别状况下形象的变动概率很小,让用户程序依赖于形象,实现的细节也依赖于形象。即便实现细节一直变动,只有形象不变,客户程序就不须要变动。这大大降低了客户程序与实现细节的耦合度。

3.4 接口隔离准则

客户端不应该被迫依赖于它不应用的办法;一个类对另一个类的依赖应该建设在最小的接口上。

接口隔离准则

package com.zhuang.principle.segregation;

/**
 * @Classname Sergregation
 * @Description 接口隔离准则
 * @Date 2021/3/15 13:02
 * @Created by dell
 */

public class Sergregation {public static void main(String[] args) {C c = new C();
        c.depend1(new A());
        c.depend2(new A());// C 类通过接口去依赖 A 类
        c.depend3(new A());

        System.out.println("=======================");

        D d = new D();
        d.depend1(new B());
        d.depend4(new B());// D 类通过接口去依赖 B 类
        d.depend5(new B());
    }
}
interface interface1{void operation1();
}

interface interface2{void operation2();
    void operation3();}

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

class A 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 B 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.....");
    }
}

// C 类通过接口 interface1,interface2 依赖应用 A 类 只会应用到 1,2,3 办法
class C{public void depend1(interface1 i){i.operation1();
    }

    public void depend2(interface2 i){i.operation2();
    }

    public void depend3(interface2 i){i.operation3();
    }
}

// D 类通过接口 interface1,interface3 依赖应用 B 类,用到 1,4,5 办法
class D{public void depend1(interface1 i){i.operation1();
    }

    public void depend4(interface3 i){i.operation4();
    }

    public void depend5(interface3 i){i.operation5();
    }
}

3.5 迪米特法令

迪米特法令又叫起码常识准则。

只和你的间接敌人交谈,不跟“陌生人”谈话(Talk only to your immediate friends and not to strangers)。

其含意是:如果两个软件实体毋庸间接通信,那么就不该当产生间接的互相调用,能够通过第三方转发该调用。其目标是升高类之间的耦合度,进步模块的绝对独立性。

迪米特法令中的“敌人”是指:以后对象自身、以后对象的成员对象、以后对象所创立的对象、以后对象的办法参数等,这些对象同以后对象存在关联、聚合或组合关系,能够间接拜访这些对象的办法。

上面看一个例子来了解迪米特法令

【例】明星与经纪人的关系实例

明星因为全身心投入艺术,所以许多日常事务由经纪人负责解决,如和粉丝的见面会,和媒体公司的业务洽淡等。这里的经纪人是明星的敌人,而粉丝和媒体公司是陌生人,所以适宜应用迪米特法令。

类图如下:

代码如下:

明星类(Star)

public class Star {
    private String name;

    public Star(String name) {this.name=name;}

    public String getName() {return name;}
}

粉丝类(Fans)

public class Fans {
    private String name;

    public Fans(String name) {this.name=name;}

    public String getName() {return name;}
}

媒体公司类(Company)

public class Company {
    private String name;

    public Company(String name) {this.name=name;}

    public String getName() {return name;}
}

经纪人类(Agent)

public class Agent {
    private Star star;
    private Fans fans;
    private Company company;

    public void setStar(Star star) {this.star = star;}

    public void setFans(Fans fans) {this.fans = fans;}

    public void setCompany(Company company) {this.company = company;}

    public void meeting() {System.out.println(fans.getName() + "与明星" + star.getName() + "见面了。");
    }

    public void business() {System.out.println(company.getName() + "与明星" + star.getName() + "洽淡业务。");
    }
}

3.6 合成复用准则

合成复用准则是指:尽量先应用组合或者聚合等关联关系来实现,其次才思考应用继承关系来实现。

通常类的复用分为继承复用和合成复用两种。

继承复用尽管有简略和易实现的长处,但它也存在以下毛病:

  1. 继承复用毁坏了类的封装性。因为继承会将父类的实现细节裸露给子类,父类对子类是通明的,所以这种复用又称为“白箱”复用。
  2. 子类与父类的耦合度高。父类的实现的任何扭转都会导致子类的实现发生变化,这不利于类的扩大与保护。
  3. 它限度了复用的灵活性。从父类继承而来的实现是动态的,在编译时曾经定义,所以在运行时不可能发生变化。

采纳组合或聚合复用时,能够将已有对象纳入新对象中,使之成为新对象的一部分,新对象能够调用已有对象的性能,它有以下长处:

  1. 它维持了类的封装性。因为成分对象的外部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
  2. 对象间的耦合度低。能够在类的成员地位申明形象。
  3. 复用的灵活性高。这种复用能够在运行时动静进行,新对象能够动静地援用与成分对象类型雷同的对象。

上面看一个例子来了解合成复用准则

【例】汽车分类管理程序

汽车按“动力源”划分可分为汽油汽车、电动汽车等;按“色彩”划分可分为红色汽车、彩色汽车和红色汽车等。如果同时思考这两种分类,其组合就很多。类图如下:

从下面类图咱们能够看到应用继承复用产生了很多子类,如果当初又有新的动力源或者新的色彩的话,就须要再定义新的类。咱们试着将继承复用改为聚合复用看一下。


写在最初

  • 如果我的文章对你有用,请给我点个👍,感激你😊!
  • 有问题,欢送在评论区指出!💪
退出移动版