面向对象设计思想+六大基本原则

面向对象的概念

万物皆对象。对象的实质是属性和行为。

类是具有共同属性和行为的对象的集合。类定义了对象的属性和方法。

面向对象编程以对象和类为主体,基本组成要素是类和对象。

是具有相同特征的对象的抽象,是一种数据类型。

基本结构

  • 属性:对象数据的描述
  • 方法:对象的行为
  • 构造方法:用于实例化对象
  • 内部类:在类中声明的类(inner class)
  • 块:分静态块与实例块
  • 类的声明:private,default final,abstract,synchronized class 类名 { 主体 }

对象

是客观实体的映射,在程序设计上对象是类的具体示例

面向对象三大要素

封装

指利用抽象数据类型把数据和操作封装在一起,用户只能看到对象的外部信息,对象的内部细节是隐藏的。

一方面封装表示对象的属性和方法是一个整体,是独立的,另一方面它表示对象的内部是隐藏的。

可以将青少年封装成一个类,有姓名、性别、年龄的属性,以及吃、睡的行为,如下:

class Teenagers {

    private String name;
    private String sex;
    private String age;

    public void eat() {
        
    }
        
    public void sleep() {
            
    }
}

继承

反映了两个类之间的一种关系,当一个类拥有另一个类的所有属性和方法时称这个类继承了另一个类,这两个类具有继承的关系,是一种创建新类的机制.

学生也是青少年,所以可以继承青少年的属性及行为;另一方面,他有自己的属性和行为。如下,学生有作业的属性,学习的行为:

class Student extends Teenagers {
    private Map<String,Object> homework;
    
    public void study() {
        
    }
}

多态

就是多种状态,即同一个实体具有多种形式。多态一般在程序运行的过程中表现出来,即同一种类型在不同条件下表现不同的结果。多态也称为动态绑定,一般在运行时刻才能确定方法的具体执行对象。

实现多态的方式:

  1. 方法重写
  2. 方法重载
  3. 父类引用指向子类对象

举例如下:

Teenagers tee = new Student();

以上就是父类的引用指向子类对象,指向了Teenager的子类对象Student。

在student中重写eat方法:

class Student extends Teenagers {
    private Map<String,Object> homework;
    
    @Override
    public void eat() {
        System.out.println("peach");
    }
    
    public void study() {
        
    }
}

调用

tee.eat();

将会打印出peach。即通过方法重写的方式实现了多态。

面向对象的设计原则

六大基本原则:

  • 单一职责原则(Single-Responsibility Principle)
  • 开闭原则(Open-Closed Principle)
  • 里氏替换原则(Liskov-Substitution Principle)
  • 接口隔离原则(Interface-Segregation Principle)
  • 依赖倒置原则(Dependency-Inversion Principle)
  • 迪米特法则(Law of Demeter)

单一职责原则

  • 基本概念:一个类只负责一个功能领域中的相应职责。就一个类而言,应该只有一个引起它变化的原因。
  • 优点:
    • 低耦合性,影响范围小
    • 降低类的复杂度,职责分明,提高了可读性
    • 变更引起的风险低,利于维护

举例:
对于一部手机有打电话,发短信,触摸控制等功能

定义接口

    // 接口定义单一职责
    interface Callable {
        void call();
    }

    interface Touchable {
        void touch();
    }

    interface Message {
        void sendMessage();
    }

    // 接口实现单一职责
    class StandardCall implements Callable {
        @Override
        public void call() {
            System.out.println("我要打电话了~");
        }
    }

    class StandardTouch implements Touchable {
        @Override
        public void touch() {
            System.out.println("我要开始触摸操作了~");
        }
    }

    class StandardMessage implements Message {
        @Override
        public void sendMessage() {
            System.out.println("我要发短信了~");
        }
    }

(上述方式完全依照单一职责原则,但在实际应用中,多选择采用针对方法的单一职责原则)
产品应用

    class Phone implements Callable, Touchable, Message {

        // 无需重新定义需要有的行为,直接用已有的
        Callable callable = new StandardCall();
        Touchable touchable = new StandardTouch();
        Message message = new StandardMessage();

        @Override
        public void call() {
            callable.call();
        }

        @Override
        public void touch() {
            touchable.touch();
        }

        @Override
        public void sendMessage() {
            message.sendMessage();
        }
    }
    
    public class Demo {

        public static void main(String[] args) {
            Phone phone = new Phone();
            phone.call();
            phone.touch();
            phone.sendMessage();
        }
    }
    

此时若我们的手机从电阻触屏更换到了电容触屏技术,只需要换掉Touchable实现类中的行为方法体,别的地方都不需要修改

    class StandardTouch implements Touchable {
        @Override
        public void touch() {
            System.out.println("我是新的电容触摸,我要开始触摸操作了~");
        }
    }

开闭原则

  • 概念:一个软件实体(软件实体可以指一个软件模块、一个由多个类组成的局部结构、一个独立的类甚至一个函数)应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
  • 优点:
    • 提高系统的灵活性、可复用性和可维护性

同样以手机为例,我们的手机拥有自己的属性和行为,在线下进行疯狂的售卖中,此时,双十一来了,要展开一波促销活动,但促销活动是暂时的。

手机类

    // 手机类
    public class SamsungPhone {

        private String model;
        private String color;
        private double price;
    
        public SamsungPhone(String model, String color, double price) {
            this.model = model;
            this.color = color;
            this.price = price;
        }
    
        public String getModel() {
            return model;
        }
    
        public String getColor() {
            return color;
        }
    
        public double getPrice() {
            return price;
        }
    }
    
    //售卖
    public class Demo {

        public static void main(String[] args) {
            SamsungPhone samsungPhone = new SamsungPhone("Galaxy S8","green",200);
            System.out.println(samsungPhone.getColor() + "的" +samsungPhone.getModel() + "售价为:" + samsungPhone.getPrice() + "元");
        }
    }
    

双十一来临,开闭原则拥抱变化,对扩展开放,对修改关闭

// 扩展促销手机类
public class SamsungSale extends SamsungPhone{

    public SamsungSale(String model, String color, double price) {
        super(model, color, price);
    }

    public double getPrice() {
        return super.getPrice() * 0.8;
    }
}

里氏替换原则

  • 概念:强调的是设计和实现要依赖于抽象而非具体;子类只能去扩展基类,而不是隐藏或者覆盖基类。即设计不要破坏继承关系。
  • 优点:
    • 开闭原则的体现,约束继承泛滥
    • 提高系统的健壮性、扩展性和兼容性

接口隔离原则

  • 概念:接口中的方法应该尽量少,不要使接口过于臃肿;接口尽量细化。
  • 优点:
    • 高内聚、低耦合
    • 可读性高、易于维护

案例:

一水果店的进货出货收银系统

违背接口隔离原则(将所有方法都集中在一个接口类中)

public interface FruitStoreInterface {
    /**
     * 计算价格
     */
    public void method1();

    /**
     * 收银
     */
    public void  method2();

    /**
     * 点货
     */
    public void method3();

    /**
     * 进货
     */
    public void method4();

    /**
     * 出货
     */
    public void method5();
}

根据接口隔离原则修改后

// 进货
public interface StockPurchaseInterface {

    /**
     * 点货
     */
    public void method3();

    /**
     * 进货
     */
    public void method4();
}

// 出货
public interface OutPurchaseInterface {
    /**
     * 出货
     */
    public void method5();
}

// 收银
public interface CalMoneyInterface {
    /**
     * 计算价格
     */
    public void method1();

    /**
     * 收银
     */
    public void  method2();
}

依赖倒置原则

  • 概念:系统抽象化的具体实现,要求面向接口编程
  • 优点:
    • 减少类间的耦合性,提高系统的稳定性
    • 降低并行开发引起的风险
    • 提高代码的可读性和可维护性

案例:

学生读书

违背依赖倒置原则设计:

// 学生类
public class Student {

    public void doSomething(YuwenBook book){
        book.readBook();
    }
}

//书本类语文
public class YuwenBook {

    public void readBook(){
        System.out.println("I am reading yuwen book!");
    }
}

//调用
public class Demo {
    public static void main(String[] args) {
        Student student = new Student();
        YuwenBook yuwenBook = new YuwenBook();
        student.doSomething(yuwenBook);
    }
}

若需求有变,我们不看语文书了,转看数学书,需要改动的地方就多了。依照依赖倒置原则修改如下:

//书本统一接口类
public interface Book {

    public void readBook();
}

//学生类
public class Student {

    public void doSomething(Book book){
        book.readBook();
    }
}

// 语文书
public class YuwenBook implements Book{

    public void readBook(){
        System.out.println("I am reading yuwen book!");
    }
}

//数学书
public class ShuxueBook implements Book {
    public void readBook() {
        System.out.println("I am reading shuxue book");
    }
}

//调用
public class Demo {
    public static void main(String[] args) {
        Student student = new Student();
        //读语文书
        YuwenBook yuwenBook = new YuwenBook();
        student.doSomething(yuwenBook);

        //读数学书
        ShuxueBook shuxueBook = new ShuxueBook();
        student.doSomething(shuxueBook);
    }
}

迪米特法则

  • 概念:一个对象应该对其他对象保持最少的了解;降低系统的耦合度,使一个模块的修改尽量少的影响其他模块,扩展会相对容易。
  • 优点:
    • 使软件有更好的可维护性和适应性
    • 对象较少依赖其他对象的内壁结构,可以改变对象容器而不用改变他的调用者

案例:
朋友A问朋友B,朋友C在干嘛,此时B也不知道,于是,B打电话给C询问

违背迪米特法则

public class FriendA {

    public String askB(FriendB b) {
        b.call();
        b.sayHello();
        b.askWhere();
        return b.askWhatDo();
    }
}

public class FriendB {

    public void call() {

    }

    public void sayHello() {

    }

    public void askWhere() {

    }

    public String askWhatDo() {
        return "跳绳";
    }
}

根据迪米特法则,A只想知道C在干嘛,而不用知道B是通过什么手段或者方式得知C的行为,修改后:

public class FriendA {

    public String askB(FriendB b) {
        return b.call();
    }
}

public class FriendB {

    public String call() {
        sayHello();
        askWhere();
        return askWhatDo();
    }

    private void sayHello() {

    }

    private void askWhere() {

    }

    private String askWhatDo() {
        return "跳绳";
    }
}

结论:面向对象的设计原则都是为了拥抱变化而研究出来的一系列捷径

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容