当前位置:首页 > 科技  > 软件

设计之魅:高质量面向对象设计的秘密

来源: 责编: 时间:2023-12-08 09:14:24 310观看
导读设计模式是在软件设计中用于解决常见问题的经过验证的解决方案。设计模式并不是代码或库,而是一种解决问题的思考方式。在使用设计模式时,需要考虑一些基本的设计原则,这些原则有助于构建灵活、可维护和可扩展的软件系统

ZwL28资讯网——每日最新资讯28at.com

设计模式是在软件设计中用于解决常见问题的经过验证的解决方案。设计模式并不是代码或库,而是一种解决问题的思考方式。在使用设计模式时,需要考虑一些基本的设计原则,这些原则有助于构建灵活、可维护和可扩展的软件系统。以下是一些常见的设计原则:ZwL28资讯网——每日最新资讯28at.com

单一职责原则(Single Responsibility Principle - SRP):

它指导我们确保一个类只有一个责任。类的责任应该是单一的,即一个类应该只有一个引起它变化的原因。这有助于提高类的内聚性,使得类更加容易理解、修改和维护。ZwL28资讯网——每日最新资讯28at.com

// 违反单一职责原则的例子class Report {    private String title;    private String content;    public Report(String title, String content) {        this.title = title;        this.content = content;    }    public void generateReport() {        // 生成报告的业务逻辑        System.out.println("Generating report for " + title + " with content: " + content);    }    public void saveToFile() {        // 将报告保存到文件的业务逻辑        String filename = title.replace(" ", "_") + ".txt";        // 实际保存到文件的代码略        System.out.println("Report saved to " + filename);    }}// 遵循单一职责原则的例子class Report {    private String title;    private String content;    public Report(String title, String content) {        this.title = title;        this.content = content;    }    public void generateReport() {        // 生成报告的业务逻辑        System.out.println("Generating report for " + title + " with content: " + content);    }}class FileSaver {    public static void saveToFile(Report report) {        // 将报告保存到文件的业务逻辑        String filename = report.getTitle().replace(" ", "_") + ".txt";        // 实际保存到文件的代码略        System.out.println("Report saved to " + filename);    }}// 上述例子中,Report 类负责生成报告,而 FileSaver 类负责将报告保存到文件。这样,每个类都有一个清晰的责任,遵循了单一职责原则。

在上述例子中,第一个示例中的 Report 类违反了单一职责原则,因为它负责生成报告和保存报告到文件两个不同的责任。在第二个示例中,将这两个责任分别放在 Report 类和 FileSaver 类中,遵循了单一职责原则,使得每个类都更加简单和可维护。这样的设计有助于将系统的不同部分解耦,提高代码的灵活性和可扩展性。ZwL28资讯网——每日最新资讯28at.com

一个类应该只有一个引起变化的原因。换句话说,一个类应该只有一个责任。ZwL28资讯网——每日最新资讯28at.com

开放/封闭原则(Open/Closed Principle - OCP):

由勃兰特·梅耶(Bertrand Meyer)提出。该原则表明一个软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。简而言之,当需要添加新功能时,应该通过扩展而不是修改现有代码来实现。ZwL28资讯网——每日最新资讯28at.com

具体来说,开放/封闭原则的核心思想是:ZwL28资讯网——每日最新资讯28at.com

开放(Open):

软件实体应该可以在不修改它的源代码的情况下进行扩展。ZwL28资讯网——每日最新资讯28at.com

新功能应该通过添加新代码来实现,而不是通过修改已有代码。ZwL28资讯网——每日最新资讯28at.com

封闭(Closed):

已有的软件实体不应该被修改,因为修改可能引入新的错误或影响现有功能的稳定性。ZwL28资讯网——每日最新资讯28at.com

这样的设计使得系统更加稳定,因为不需要修改现有代码,只需要添加新的代码。这也有助于降低代码的耦合性,提高代码的可维护性和可扩展性。ZwL28资讯网——每日最新资讯28at.com

// 违反开放/封闭原则的例子class Rectangle {    public double width;    public double height;    public Rectangle(double width, double height) {        this.width = width;        this.height = height;    }}class AreaCalculator {    public double calculateRectangleArea(Rectangle rectangle) {        return rectangle.width * rectangle.height;    }}// 上述代码违反了开放/封闭原则,如果要添加一个新的形状(例如圆形),就需要修改 AreaCalculator 类。// 遵循开放/封闭原则的例子interface Shape {    double calculateArea();}class Rectangle implements Shape {    private double width;    private double height;    public Rectangle(double width, double height) {        this.width = width;        this.height = height;    }    @Override    public double calculateArea() {        return width * height;    }}class Circle implements Shape {    private double radius;    public Circle(double radius) {        this.radius = radius;    }    @Override    public double calculateArea() {        return Math.PI * radius * radius;    }}class AreaCalculator {    public double calculateShapeArea(Shape shape) {        return shape.calculateArea();    }}// 上述代码遵循了开放/封闭原则,通过引入 Shape 接口和不同的形状类,可以轻松地添加新的形状而无需修改 AreaCalculator 类。

在遵循开放/封闭原则的例子中,通过引入一个 Shape 接口和不同的形状类(例如 Rectangle 和 Circle),可以轻松地添加新的形状而无需修改 AreaCalculator 类。这样,系统的扩展性得到了提高,同时保持了对现有代码的封闭性。ZwL28资讯网——每日最新资讯28at.com

软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着在不修改现有代码的情况下,可以通过添加新的代码来扩展系统的功能。ZwL28资讯网——每日最新资讯28at.com

里氏替换原则(Liskov Substitution Principle - LSP):

由计算机科学家巴巴拉·利斯科夫(Barbara Liskov)提出。该原则指导着子类型(派生类或子类)如何与基类型(基类或父类)进行替换,以确保程序的正确性和一致性。ZwL28资讯网——每日最新资讯28at.com

如果对每一个类型为 S 的对象 o1,都有类型为 T 的对象 o2,使得以 T 定义的所有程序 P 在所有的对象 o1 都替换成 o2 时,程序 P 的行为没有发生变化,那么类型 S 是类型 T 的子类型。ZwL28资讯网——每日最新资讯28at.com

换句话说,如果子类型可以替换父类型而不影响程序的正确性,那么这个子类型是符合里氏替换原则的。ZwL28资讯网——每日最新资讯28at.com

// 违反里氏替换原则的例子class Rectangle {    protected int width;    protected int height;    public void setWidth(int width) {        this.width = width;    }    public void setHeight(int height) {        this.height = height;    }    public int calculateArea() {        return width * height;    }}class Square extends Rectangle {    @Override    public void setWidth(int width) {        super.setWidth(width);        super.setHeight(width);    }    @Override    public void setHeight(int height) {        super.setHeight(height);        super.setWidth(height);    }}// 上述代码违反了里氏替换原则,因为在Square类中重写了setWidth和setHeight方法,导致Square对象在替换Rectangle对象时可能会引发意料之外的行为。// 遵循里氏替换原则的例子class Shape {    protected int width;    protected int height;    public void setWidth(int width) {        this.width = width;    }    public void setHeight(int height) {        this.height = height;    }    public int calculateArea() {        return width * height;    }}class Rectangle extends Shape {    // 省略特有的方法或属性}class Square extends Shape {    @Override    public void setWidth(int side) {        super.setWidth(side);        super.setHeight(side);    }    @Override    public void setHeight(int side) {        super.setHeight(side);        super.setWidth(side);    }}// 上述代码遵循了里氏替换原则,因为Square类继承自Shape类,没有修改基类的行为,而是通过适当的方式扩展了基类的功能。

在遵循里氏替换原则的例子中,Square类不再继承自Rectangle类,而是继承自一个通用的Shape类,确保子类型可以被替换而不引起意外的行为变化。通过这种方式,程序可以更灵活地使用不同的形状类型,而不必担心替换时可能引发的问题。ZwL28资讯网——每日最新资讯28at.com

子类型必须能够替换其基类型而不改变程序的正确性。如果一个类是某个抽象类的子类,那么它应该能够替代该抽象类的任何地方,并且程序的行为不会改变。ZwL28资讯网——每日最新资讯28at.com

依赖倒置原则(Dependency Inversion Principle - DIP):

由罗伯特·马丁(Robert C. Martin)提出。该原则主要有两个核心观点:ZwL28资讯网——每日最新资讯28at.com

  • 高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
  • 抽象不应该依赖于细节,细节应该依赖于抽象。

在设计系统时,应该通过依赖于抽象而不是具体实现来减少模块之间的耦合。高层模块和低层模块都应该依赖于通用的抽象,而不是彼此直接依赖。这有助于提高系统的灵活性、可维护性和可扩展性。ZwL28资讯网——每日最新资讯28at.com

// 违反依赖倒置原则的例子class LightBulb {    public void turnOn() {        System.out.println("LightBulb: Bulb turned on...");    }    public void turnOff() {        System.out.println("LightBulb: Bulb turned off...");    }}class Switch {    private LightBulb bulb;    public Switch() {        this.bulb = new LightBulb();    }    public void operate() {        if (bulb != null) {            if (bulb.isOn()) {                bulb.turnOff();            } else {                bulb.turnOn();            }        }    }}// 上述代码违反了依赖倒置原则,因为Switch类直接依赖于具体的LightBulb类。// 遵循依赖倒置原则的例子interface Switchable {    void turnOn();    void turnOff();}class LightBulb implements Switchable {    @Override    public void turnOn() {        System.out.println("LightBulb: Bulb turned on...");    }    @Override    public void turnOff() {        System.out.println("LightBulb: Bulb turned off...");    }}class Switch {    private Switchable device;    public Switch(Switchable device) {        this.device = device;    }    public void operate() {        if (device != null) {            if (device.isOn()) {                device.turnOff();            } else {                device.turnOn();            }        }    }}// 上述代码遵循了依赖倒置原则,Switch类依赖于通用的Switchable接口而不是具体的LightBulb类。

在遵循依赖倒置原则的例子中,Switch 类不再直接依赖于 LightBulb 类,而是依赖于通用的 Switchable 接口。这样,如果有其他类实现了 Switchable 接口,可以轻松地替换 LightBulb 类,而不影响 Switch 类的实现。这提高了系统的灵活性和可维护性。ZwL28资讯网——每日最新资讯28at.com

高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。这促使使用接口或抽象类来减少模块之间的耦合。ZwL28资讯网——每日最新资讯28at.com

接口隔离原则(Interface Segregation Principle - ISP):

接口隔离原则(Interface Segregation Principle - ISP)是面向对象设计中的一个原则,它强调一个类不应该被强迫依赖于它不使用的接口。该原则的目标是防止一个类因为实现了不需要的接口而变得庞大臃肿,降低类的内聚性。ZwL28资讯网——每日最新资讯28at.com

接口隔离原则可以通过将大接口拆分成更小的、更具体的接口来实现。具体来说,一个类只应该知道它需要使用的方法,而不需要了解其他不相关的方法。ZwL28资讯网——每日最新资讯28at.com

// 违反接口隔离原则的例子interface Worker {    void work();    void eat();}class Robot implements Worker {    @Override    public void work() {        System.out.println("Robot is working...");    }    @Override    public void eat() {        // 空实现,机器人无需进食    }}class Human implements Worker {    @Override    public void work() {        System.out.println("Human is working...");    }    @Override    public void eat() {        System.out.println("Human is eating...");    }}// 上述代码违反了接口隔离原则,因为Robot类实现了不需要的eat方法。// 遵循接口隔离原则的例子interface Workable {    void work();}interface Eatable {    void eat();}class Robot implements Workable {    @Override    public void work() {        System.out.println("Robot is working...");    }}class Human implements Workable, Eatable {    @Override    public void work() {        System.out.println("Human is working...");    }    @Override    public void eat() {        System.out.println("Human is eating...");    }}// 上述代码遵循了接口隔离原则,将大接口拆分成Workable和Eatable两个小接口,类只需要实现它们真正需要的接口。

在遵循接口隔离原则的例子中,将大接口拆分成 Workable 和 Eatable 两个小接口。这样,Robot 类只需实现 Workable 接口,而 Human 类则同时实现了 Workable 和 Eatable 接口。这避免了类实现不需要的方法,提高了系统的灵活性和可维护性。ZwL28资讯网——每日最新资讯28at.com

不应该强迫客户端依赖于它们不使用的接口。一个类不应该被迫实现它用不到的接口。ZwL28资讯网——每日最新资讯28at.com

合成/聚合复用原则(Composition/Aggregation Reuse Principle - CARP):

合成/聚合复用原则(Composition/Aggregation Reuse Principle - CARP)是面向对象设计中的一个原则,它强调在复用时优先使用组合(Composition)和聚合(Aggregation),而不是继承。该原则的核心思想是通过将现有的类组合在一起来创建新的类,而不是通过继承现有类。ZwL28资讯网——每日最新资讯28at.com

合成/聚合复用原则的主要原则有两个:ZwL28资讯网——每日最新资讯28at.com

优先使用合成(Composition):

通过将对象组合在一起来创建新的对象,而不是通过继承现有类。这样可以更灵活地构建对象的行为,而不会产生继承链的问题。ZwL28资讯网——每日最新资讯28at.com

优先使用聚合(Aggregation):

聚合是一种特殊的合成关系,表示一种“整体-部分”的关系,但整体和部分之间的生命周期可以独立存在。这允许部分对象在没有整体对象的情况下存在。与合成一样,聚合也提供了更灵活的复用方式。ZwL28资讯网——每日最新资讯28at.com

// 违反合成/聚合复用原则的例子class Engine {    public void start() {        System.out.println("Engine starting...");    }}class Car extends Engine {    public void drive() {        System.out.println("Car is driving...");    }}// 上述代码违反了合成/聚合复用原则,因为Car类通过继承Engine类,导致Car和Engine之间形成了紧耦合的关系。// 遵循合成/聚合复用原则的例子class Engine {    public void start() {        System.out.println("Engine starting...");    }}class Car {    private Engine engine;    public Car(Engine engine) {        this.engine = engine;    }    public void drive() {        engine.start();        System.out.println("Car is driving...");    }}// 上述代码遵循了合成/聚合复用原则,Car类通过组合引入了Engine类,而不是通过继承。这降低了类之间的耦合性,使得系统更加灵活。

在遵循合成/聚合复用原则的例子中,Car 类通过组合引入了 Engine 类,而不是通过继承。这降低了类之间的耦合性,使得系统更加灵活,更容易进行复用和维护。使用合成和聚合的方式可以避免继承链的问题,并提高系统的灵活性。ZwL28资讯网——每日最新资讯28at.com

首选使用合成/聚合,而不是继承。通过将现有类的实例组合到新的类中,而不是通过继承现有类来实现代码复用。ZwL28资讯网——每日最新资讯28at.com

迪米特法则(Law of Demeter - LoD):

迪米特法则(Law of Demeter - LoD),也被称为最少知识原则,是面向对象设计中的一项原则。迪米特法则强调一个对象应该对其他对象有最少的了解,即一个类不应该直接与其他类过多地发生相互作用。ZwL28资讯网——每日最新资讯28at.com

一个对象应该对其他对象保持最少的了解。只与你的直接朋友通信,而避免和陌生人通信。ZwL28资讯网——每日最新资讯28at.com

这意味着一个类应该尽量减少对其他类的引用,尽量减少依赖关系,以降低类之间的耦合度。通过保持对象之间的关系简单,可以提高系统的灵活性和可维护性。ZwL28资讯网——每日最新资讯28at.com

// 违反迪米特法则的例子class Teacher {    public void instruct(Student student) {        // 教师直接与学生对象发生交互        student.study();    }}class Student {    public void study() {        System.out.println("Student is studying...");    }}// 上述代码违反了迪米特法则,因为Teacher类直接与Student类发生了交互。// 遵循迪米特法则的例子class Teacher {    public void instruct(StudentProxy studentProxy) {        // 教师只与学生代理对象发生交互,而不直接与学生对象交互        studentProxy.study();    }}class Student {    public void study() {        System.out.println("Student is studying...");    }}class StudentProxy {    private Student student;    public StudentProxy(Student student) {        this.student = student;    }    public void study() {        // 通过代理对象转发请求给学生对象        student.study();    }}// 上述代码遵循了迪米特法则,Teacher类只与StudentProxy类发生交互,而不直接与Student类发生交互。

在遵循迪米特法则的例子中,Teacher 类只与 StudentProxy 类发生交互,而不直接与 Student 类发生交互。这样,Teacher 类不需要了解 Student 类的内部实现,通过 StudentProxy 类进行间接的交互。这降低了类之间的耦合度,符合迪米特法则的要求。ZwL28资讯网——每日最新资讯28at.com

一个软件实体应当尽可能少地与其他实体发生相互作用。也被称为最少知识原则。ZwL28资讯网——每日最新资讯28at.com

在面向对象设计中,设计原则是指导我们创建灵活、可维护、可扩展软件系统的重要指导方针。每个设计原则都强调特定的方面,例如单一职责原则、开放/封闭原则、里氏替换原则、依赖倒置原则、接口隔离原则和合成/聚合复用原则。这些原则共同构建了一个强大的设计基础,有助于在面对不断变化的需求时更好地应对挑战。ZwL28资讯网——每日最新资讯28at.com

在实际开发中,理解并应用这些设计原则是至关重要的。它们提供了一组指导原则,帮助自己构建出更加健壮和灵活的软件系统。通过不断学习和实践,可以更好地运用这些原则来创建高质量的面向对象设计。ZwL28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-39508-0.html设计之魅:高质量面向对象设计的秘密

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 这套分布式IM即时通讯系统如何写到简历上?我给你整理好了!

下一篇: 探索Spring Boot中@PostConstruct的魔法

标签:
  • 热门焦点
  • 影音体验是真的强 简单聊聊iQOO Pad

    大公司的好处就是产品线丰富,非常细分化的东西也能给你做出来,例如早先我们看到了新的vivo Pad2,之后我们又在iQOO Neo8 Pro的发布会上看到了iQOO的首款平板产品iQOO Pad。虽
  • iPhone卖不动了!苹果股价创年内最大日跌幅:市值一夜蒸发万亿元

    8月5日消息,今天凌晨美股三大指数高开低走集体收跌,道指跌0.41%;纳指跌0.36%;标普500指数跌0.52%。热门科技股也都变化极大,其中苹果报181.99美元,跌4.8%,创
  • K8S | Service服务发现

    一、背景在微服务架构中,这里以开发环境「Dev」为基础来描述,在K8S集群中通常会开放:路由网关、注册中心、配置中心等相关服务,可以被集群外部访问;图片对于测试「Tes」环境或者
  • 破圈是B站头上的紧箍咒

    来源 | 光子星球撰文 | 吴坤谚编辑 | 吴先之每年的暑期档都少不了瞄准追剧女孩们的古偶剧集,2021年有优酷的《山河令》,2022年有爱奇艺的《苍兰诀》,今年却轮到小破站抓住了追
  • 拼多多APP上线本地生活入口,群雄逐鹿万亿市场

    Tech星球(微信ID:tech618)文 | 陈桥辉 Tech星球独家获悉,拼多多在其APP内上线了“本地生活”入口,位置较深,位于首页的“充值中心”内,目前主要售卖美食相关的
  • 华为Mate60标准版细节曝光:经典星环相机模组回归

    这段时间以来,关于华为新旗舰的爆料日渐密集。据此前多方爆料,今年华为将开始恢复一年双旗舰战略,除上半年推出的P60系列外,往年下半年的Mate系列也将
  • Android 14发布:首批适配机型公布

    5月11日消息,谷歌在今天凌晨举行了I/O大会,本次发布会谷歌带来了自家的AI语言模型PaLM 2、谷歌Pixel Fold折叠屏、谷歌Pixel 7a手机,同时发布了Androi
  • 电博会与软博会实现"线下+云端"的双线融合

    在本次“电博会”与“软博会”双展会利好条件的加持下,既可以发挥展会拉动人流、信息流、资金流实现快速交互流动的作用,继而推动区域经济良性发展;又可以聚
  • Meta盲目扩张致超万人被裁,重金押注元宇宙而前景未明

    图片来源:图虫创意日前,Meta创始人兼CEO 马克·扎克伯发布公开信,宣布Meta计划裁员超11000人,占其员工总数13%。他公开承认了自己的预判失误:“不仅
Top