Java设计模式-面向对象7大原则

1、面向对象7大原则

**1、开闭原则:**对扩展开放,对修改改变。

**2、里氏替换原则:**只要父类出现的地方,子类都可以替换他,使用者可能都不知道到底是子类还是父类(就是子类继承了超类,在子类中保持超类的特性)

**3、单一职责原则:**对类来说,就是一个类应该只负责一项职责。

**4、依赖倒置原则:**要面向接口编程,不要面向实现编程。

**5、接口隔离原则:**客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。

**6、迪米特原则:**一个类对自己依赖的其他类知道的越少越好。

**7、合成复用原则:**尽量先使用组合或聚合等关联关系,其次才考虑使用继承关系来实现。

1.1 单一职责原则

对类来说,就是一个类应该只负责一项职责,这就是单一职责原则。

违反单一职责原则例子:

public class SingleReponsibility1 {
    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 + " 在公路上跑");
    }
}

单一职责原则例子:

public class SingleReponsibility1 {
    public static void main(String[] args) {
        RoadVehicle roadVehicle = new RoadVehicle();
        roadVehicle.run("汽车");  //输出: 汽车 在公路上跑
        roadVehicle.run("摩托车");//输出: 摩托车 在公路上跑
        AirVehicle airVehicle = new AirVehicle();
        airVehicle.run("飞机");//输出: 飞机 在天上跑
    }
}

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

//空中交通工具类
class AirVehicle {
    public void run(String vehicle){
        System.out.println(vehicle + " 在天上跑");
    }
}

不过上面这个例子不是最好的,变成这个例子例子改动太大,最好是使用接口+多态的方式。

总结:

  1. 降低类的复杂度,一个类只负责一项职责。
  2. 提高类的可读性,可维护性。
  3. 减低变更引起的风险。
  4. 只有类的方法比较少,可以只在方法级别保持单一原则。

1.2 接口隔离原则

客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。

违反接口隔离原则:

类B、D都实现了接口interface1,类A只需要使用到B的operation1和operation3方法,类C只需要用到D的operation2和operation4方法,这样就是 依赖了所不需要的接口了。

在这里插入图片描述

public class SegregationTest {
    public static void main(String[] args) {
        A a = new A();
        a.dependOn1(new B());
        a.dependOn3(new B());
        C c = new C();
        c.dependOn2(new D());
        c.dependOn4(new D());
    }
}

interface interface1{
    void operation1();
    void operation2();
    void operation3();
    void operation4();
}

class B implements interface1{   //B只被用到了operation1和operation3方法,却实现了所有接口方法。
    @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");
    }
}

class D implements interface1{   //D只被用到了operation2和operation4方法,却实现了所有接口。
    @Override
    public void operation1() {
        System.out.println("D 实现了 operation1");
    }

    @Override
    public void operation2() {
        System.out.println("D 实现了 operation2");
    }

    @Override
    public void operation3() {
        System.out.println("D 实现了 operation3");
    }

    @Override
    public void operation4() {
        System.out.println("D 实现了 operation4");
    }
}

class A{   //A只需要B的operation1和operation3方法
    public void dependOn1(interface1 i){
        i.operation1();
    }
    public void dependOn3(interface1 i){
        i.operation3();
    }
}

class C{  //只需要用到D的operation2和operation4方法
    public void dependOn2(interface1 i){
        i.operation2();
    }
    public void dependOn4(interface1 i){
        i.operation4();
    }
}

正确例子:

进行接口分离。

public class SegregationTest {
    public static void main(String[] args) {
        A a = new A();
        a.dependOn1(new B());
        a.dependOn3(new B());
        C c = new C();
        c.dependOn2(new D());
        c.dependOn4(new D());
    }
}

interface interface1{
    void operation1();
    void operation3();
}

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

class B implements interface1{
    @Override
    public void operation1() {
        System.out.println("B 实现了 operation1");
    }

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

class D implements interface2{
    @Override
    public void operation2() {
        System.out.println("D 实现了 operation2");
    }

    @Override
    public void operation4() {
        System.out.println("D 实现了 operation4");
    }
}

class A{
    public void dependOn1(interface1 i){
        i.operation1();
    }
    public void dependOn3(interface1 i){
        i.operation3();
    }
}

class C{
    public void dependOn2(interface2 i){
        i.operation2();
    }
    public void dependOn4(interface2 i){
        i.operation4();
    }
}

1.3 依赖倒置原则

依赖倒置原则:

  1. 高层模块不应该依赖底层模块,二者都应该依赖其抽象。(高层理解为吃动作,底层理解为面包等具体食物)
  2. 抽象不应该依赖细节,细节应该依赖抽象。
  3. 依赖倒置的中心思想就是面向接口编程

在继承时要遵循里氏替换原则。

错误示例:

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

//电子邮箱类
class Email{
    public String getInfo(){
        return "获得电子邮件信息";
    }
}

//完成Person接受消息的功能
//缺点:如果要接受消息的对象是 微信类、短信类,就得增加相应的方法。
class Person{
    public void receive(Email email){
        System.out.println(email.getInfo());
    }
}

解决示例:

引入一个抽象的接口IReceiver,表示接收者,这样Person类就只与接口发送依赖

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

interface IReceiver{
    String getInfo();
}

//电子邮箱类
class Email implements IReceiver{
    public String getInfo(){
        return "获得电子邮件信息";
    }
}

//微信类
class Wechat implements IReceiver{
    @Override
    public String getInfo() {
        return "获得微信信息";
    }
}

//完成Person接受消息的功能
class Person{
    //这样就不需要每添加一个消息对象就写相应的方法
    public void receive(IReceiver receiver){
        System.out.println(receiver.getInfo());
    }
}

上面的示例是基于接口实现的,下面的示例是基于构造函数来实现的:

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

interface IReceiver{
    String getInfo();
}

//电子邮箱类
class Email implements IReceiver{
    public String getInfo(){
        return "获得电子邮件信息";
    }
}

//微信类
class Wechat implements IReceiver{
    @Override
    public String getInfo() {
        return "获得微信信息";
    }
}

//完成Person接受消息的功能
class Person{
    private IReceiver iReceiver;

    public Person(IReceiver iReceiver) {
        this.iReceiver = iReceiver;
    }

    public void receive(){
        System.out.println(iReceiver.getInfo());
    }
}

下面的示例是基于setter方法来实现:

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

interface IReceiver{
    String getInfo();
}

//电子邮箱类
class Email implements IReceiver{
    public String getInfo(){
        return "获得电子邮件信息";
    }
}

//微信类
class Wechat implements IReceiver{
    @Override
    public String getInfo() {
        return "获得微信信息";
    }
}

//完成Person接受消息的功能
class Person{
    private IReceiver iReceiver;

    public void setiReceiver(IReceiver iReceiver) {
        this.iReceiver = iReceiver;
    }

    public void receive(){
        System.out.println(iReceiver.getInfo());
    }
}

1.4 里氏替换原则

**里氏替换原则:**所有引用基类(父类)的地方必须能透明地使用其子类的对象。也就是说子类可以扩展父类的功能,但不能改变父类原有功能。

透明使用的关键就是,子类不能改变父类原有功能。

错误示例:子类改变了父类原有功能后,当我们在引用父类的地方使用其子类的时候,没办法透明使用add方法了。

public class Test53 {
    public static void main(String[] args) {
        //当我们在引用父类的地方使用其子类的时候,无法透明的使用add方法
        Person person = new Children();
        person.add();
    }
}

class Person{
    public void add(){
        System.out.println("父类");
    }
}

class Children extends Person{
    public void add(){
        System.out.println("子类");
    }
}

正确示例:将原来的父类和子类都继承一个更通俗的基类(抽象类)。

public class Test53 {
    public static void main(String[] args) {
       // Person person = new Children();  这个用不了
        All all = new Person();
        all.add();
        all = new Children();
        all.add();
    }
}

abstract class All{
    public abstract void add();
}

class Person extends All{
    public void add(){
        System.out.println("父类");
    }
}

class Children extends All{
    public void add(){
        System.out.println("子类");
    }
}

1.5 开闭原则

**开闭原则:**对扩展开发,对修改关闭。

错误示例:

public class OcpTest {
    public static void main(String[] args) {
        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Retangle());
        graphicEditor.drawShape(new Circle());
    }
}

//绘制图形的类
class GraphicEditor{
    //当我再加一个图形时,这个方法就必须改动。不符合对修改关闭。
    public void drawShape(Shape shape){
        if(shape.type==1){
            drawRetangle();
        }else if(shape.type==2){
            drawCircle();
        }
    }

    public void drawRetangle(){
        System.out.println("绘制矩形");
    }

    public void drawCircle(){
        System.out.println("绘制圆形");
    }
}

//图形类
class Shape {
    int type;
}

//矩形类
class Retangle extends Shape {
    public Retangle() {
        super.type = 1;
    }
}

//圆形类
class Circle extends Shape {
    public Circle() {
        super.type = 2;
    }
}

正确示例:使用抽象类。

public class OcpTest {
    public static void main(String[] args) {
        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Retangle());
        graphicEditor.drawShape(new Circle());
    }
}

//绘制图形的类
class GraphicEditor{
    public void drawShape(Shape shape){
       shape.draw();
    }
}

//图形类
abstract class Shape {
    abstract public void draw();
}

//矩形类
class Retangle extends Shape {
    @Override
    public void draw() {
        System.out.println("绘制矩形");
    }
}

//圆形类
class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }
}

1.6 迪米特法则

**迪米特法则(又称最小知道法则):**一个类对自己依赖的其他类知道的越少越好。

一个对象应该对其他对象有最少的了解要满足这两点:

  1. 只和直接朋友交流。
  2. 减少对朋友的了解。

**直接朋友:**出现在成员变量、方法的返回类型,方法参数就是直接的朋友。(只出现在方法体内部的类不是直接朋友)

**迪米特法则的目的:**减低类之间的耦合度,但并不是要求完全没有依赖关系。

错误示例:

public class DemeterTest {
    public static void main(String[] args) {
        Person person = new Person();
        person.washClothes();
    }
}

//洗衣机类
class WashingMachine{
    public void receiveClothes(){
        System.out.println("洗衣街接收到了衣服");
    }

    public void wash(){
        System.out.println("洗衣机洗衣服");
    }

    public void dry(){
        System.out.println("洗衣机烘干衣服");
    }
}

//人
class Person{
    //让洗衣机洗衣服的方法
    public void washClothes(){
        //由人来指定洗衣机洗衣服的顺序,Person类对WashingMachine类知道的太多。
        WashingMachine washingMachine = new WashingMachine();
        washingMachine.receiveClothes();
        washingMachine.wash();
        washingMachine.dry();
    }
}

正确示例:

public class DemeterTest {
    public static void main(String[] args) {
        Person person = new Person();
        person.washClothes(new WashingMachine());
    }
}

//洗衣机类
class WashingMachine{
    public void receiveClothes(){
        System.out.println("洗衣街接收到了衣服");
    }

    public void wash(){
        System.out.println("洗衣机洗衣服");
    }

    public void dry(){
        System.out.println("洗衣机烘干衣服");
    }

    public void autoWash(){
        receiveClothes();
        wash();
        dry();
    }
}

//人
class Person{
    //让洗衣机洗衣服的方法
    public void washClothes(WashingMachine washingMachine){
        washingMachine.autoWash();
    }
}

1.7 合成复用原则

原则是尽量使用合成/聚合的方式。而不是使用继承。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值