设计模式-SOLID原则

我参考的资料:
c语言中文网_软件设计模式概述
菜鸟设计模式
设计模式六大原则
《Android源码设计模式解析与实战》
《Android进阶之光》

设计模式分类

常见一共有23种,根据他们的行为可以分为三种,

  • 一种是创建型模式包含5种(单例、工厂、抽象工厂、建造者、原型);
  • 第二种行为型模式包含11种(策略、模板、观察者、迭代器、责任链、命令、备忘录,状态、访问者、中介者、解释器);
  • 第三种结构型模式包含7种(适配器、装饰、代理、外观、桥接、组合、享元);

重要的思想↓

如果上面太多没记住或者太多了还没学咋整,就是要牢记于心,把下面6个原则 SOLID+Lod原则给融入自己写的每一行代码。
S: single responsibility principle 单一原则
O:open close principle 开闭原则
L: Liskov substitution principle 里氏替换原则
I: interface segregation principle 接口隔离原则
D: dependence inversion principle 依赖倒置原则
Lod: law of Demeter 迪米特法则(LKP least knowledge principle 最少知识原则)
还有个CRP 合成复用原则(Composite Reuse Principle)

单一原则SRP

书面描述:一个类是一堆相关性很高的方法和数据的封装,有且只有一个原因导致他更改。我的理解就是你一个方法是初始化就初始化,是播放就别干暂停的事情。对音乐文件编解码啥的跟播放有关系,但是是另一个职能,也给他抽离出去。一个类最好针对一个事情,比如你是个屏幕尺寸的工具类,就别放点什么保存文件之类的方法。

public void playMusic() {
//判断当前是否播放,再抽个方法
  if(isPlaying) {
     playManager.stop();
     playManager.someThing();
  }
//初始化,再抽个方法
thisSong.prepare();
thisSong.setParams();
playManager.start(thisSong);
}

public void playMusic(Song thisSong) {
  checkPlayState();
  prepareSong();
  playManager.start(thisSong);
}

开闭原则OCP

书面描述就是对修改是关闭的,对于扩展是开放的;可以通过“抽象约束、封装变化”来实现开闭原则,即通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。我理解就是都开发完了,要加新需求的时候,看看咋样才能不改原来的逻辑,然后还能给她加上新逻辑的。看看是不是一个事情要两个实现方案换着来,或者是加了新的功能。只要是一看要修改原来的代码,看看能不能通过抽取父类然后建立多个不同实现的子类,或者通过抽象接口,给他不同实现类啥的。

//开闭原则
public class OCPTest {
    public static void main(String[] args) {
        OCP ocp = new OCP();
        //最开始我喜欢的哥哥,我自己组cp
        ocp.createCP4GeGe();
        //后来为了火跟别的流量大佬组cp
        ocp.createCP4GeGe("with_popular_star");
        //cp类型太多,交给了个组织,每个人负责一个不同类型的cp
        ocp.createCP(new AdvertisingOCP());
        //让跟一个会rap的人组cp
        ocp.createCP(new RapCP());
        //让哥哥会Rap...
        ocp = new RapOCP();
        ocp.createCP(new RapCP());

        //上面这个大概是我理解的OCP了
    }

    static class OCP {
        //最开始的方法
        public void createCP4GeGe() {
            System.out.println("gege跟我喜欢的明星在一起");
        }


        //需求逐渐增多,每增加一个都要改动这个方法。。。nonono
        public void createCP4GeGe(String type) {
            switch (type) {
                case "with_popular_star":
                    System.out.println("蹭热度cp");
                    break;
                case "to_promote_new_movie":
                    System.out.println("给新剧打广告cp");
                    break;
            }
        }

        public void createCP(OhCP cp) {
            cp.createCP();
        }

    }

    static class RapOCP extends OCP {

        @Override
        public void createCP(OhCP cp) {
            System.out.println("我也会rap");
            super.createCP(cp);
        }
    }

    interface OhCP {
        void createCP();
    }

    static class RapCP implements OhCP {

        String getSkill() {
            return "rap";
        }

        @Override
        public void createCP() {
            System.out.printf("cp会%s", getSkill());
            System.out.println();
        }
    }

    static class AdvertisingOCP implements OhCP {

        @Override
        public void createCP() {
            System.out.println("给新剧打广告cp");
        }
    }
}


上面那个例子估计有人问(我自己问:为啥有的用接口,有的用超类继承呢。。主要考虑到一个复用,还有一个是功能抽象接口和抽象类的区别)

里氏替换原则LSP

书面描述:所有引用基类的地方必须能透明地使用其子类的对象。我的理解是这个就要说到抽象和继承了,就是爸爸出现的地方都能替换成儿子,依赖抽象不依赖具体。比如爸爸(父类)已经跟买家定好了你先给钱,我后给货。那具体是大儿子取现金钱开车送货,还是二儿子刷卡开船送货都行,但是儿子不能更改爸爸定下的规矩(可以扩展,但是不能重写父类的方法)

public class LSPTest {
    public static void main(String[] args) {
        LSP lsp = new LSPSon1();
        lsp.chargeMoney();
        lsp.deliverCargo();
    }


    static abstract class LSP {
        abstract void chargeMoney();

        abstract void deliverCargo();
    }

    static class LSPSon1 extends LSP {

        @Override
        void chargeMoney() {
            System.out.println("show me cash");
        }

        @Override
        void deliverCargo() {
            System.out.println("deliveries in a BMW");
        }
    }

    static class LSPSon2 extends LSP {

        @Override
        void chargeMoney() {
            System.out.println("credit card please");
        }

        @Override
        void deliverCargo() {
            System.out.println("deliveries with my jetSki");
        }
    }

}

接口隔离原则ISP

书面描述:一个类对另一个类的依赖应该建立在最小的接口上。我理解就是接口是抽象的功能定义,我一个类可以被复制、被比较、被读写,我抽取的时候把这个类的基本属性比如名字、id这些属性抽到了抽象类里,然后把它具有的这些特性都抽到一个功能接口A里,但是第二个类只能被读写,不能被复制、不能比较,那他也实现A的话,会有一些他不支持的属性,所以可以对A进行划分,比较A接口、复制B接口、读写C接口,如果还有个只支持读不支持写的类,看看是不是再划分一下C接口,这样实现类不会被强制实现一些用不到的方法。

//接口隔离原则
public class ISPTest {
    
    interface IIO {
        void read();
        void write();
    }
    interface ICopy {
        void copy();
    }
    interface ICompare {
        void compareTo(Object obj);
    }
    
    interface IAllFunction {
        void read();
        void write();
        void copy();
        void compareTo(Object obj);
    }
    
    class BookFile implements  IAllFunction{

        @Override
        public void read() {
            
        }

        @Override
        public void write() {

        }

        @Override
        public void copy() {

        }

        @Override
        public void compareTo(Object obj) {

        }
    }
    
    class BookFileII implements IIO,ICompare{

        @Override
        public void read() {
            
        }

        @Override
        public void write() {

        }

        @Override
        public void compareTo(Object obj) {
            
        }
    }
    
}

依赖倒置原则DIP

书面描述:高层模块不应该依赖于底层模块,两者应该依赖于其抽象;抽象不应该依赖具体实现(实现类),具体实现应该依赖抽象(接口或者抽象类)。我理解就是一个A调用我的方法,不是调我,是调我爸爸的抽象方法,他俩定义了个规则,然后具体实现让子类实现。面向接口编程了。

依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合

//依赖倒置原则
public class DIPTest {
    public static void main(String[] args) {
        Me me = new Me();
        me.eatChipWithKetchup(new Ketchup());
        me.eatChipWithCheese(new Cheese());
        me.eatChipWithDip(new AppleSauce());
        me.eatChipWithDip(new RoseJam());
    }

    static class Me {
        //最开始我只吃番茄酱
        void eatChipWithKetchup(Ketchup ketchup) {
            ketchup.eatMe();
        }

        //后来我知道还有芝士酱
        void eatChipWithCheese(Cheese cheese) {
            cheese.eatMe();
        }

        //我爱的东西越来越多,我想蘸苹果酱
        void eatChipWithAppleSauce() {
            System.out.println("吃薯条蘸苹果酱");
        }

        //我不想每次换酱都写方法,直接让我跟蘸酱爸爸沟通,让他每次给我不同儿子就行
        void eatChipWithDip(IDip dip) {
            System.out.printf("吃薯条蘸%s", dip.getType());
        }
    }

    interface IDip {
        String getType();
    }

    static class Ketchup {
        void eatMe() {
            System.out.println("吃薯条蘸番茄酱");
        }
    }

    static class Cheese {
        void eatMe() {
            System.out.println("吃薯条蘸芝士酱");
        }
    }

    static class AppleSauce implements IDip {

        @Override
        public String getType() {
            return "苹果酱";
        }
    }

    static class RoseJam implements IDip {

        @Override
        public String getType() {
            return "玫瑰酱";
        }
    }
}

迪米特法则LOD/最少知识原则LKP

书面描述:一个类应该对其他对象有最少的了解/只与直接的朋友通信(成员变量,方法参数,方法返回值中的类为直接朋友)(而出现在局部变量中的类不是直接的朋友)我理解就是每个类都做甩手掌柜,事情吩咐下去了,不管你是怎么实现的,我只用跟你说一声调你一个方法,该给你的信息告诉你,最后你干完这个事情就行了。
这个是从c语言中文网抄的,有些我还不太能用自己的话说出来,贴这里

从迪米特法则的定义和特点可知,它强调以下两点:
从依赖者的角度来说,只依赖应该依赖的对象。
从被依赖者的角度说,只暴露应该暴露的方法。

所以,在运用迪米特法则时要注意以下 6 点。
在类的划分上,应该创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标。
在类的结构设计上,尽量降低类成员的访问权限。
在类的设计上,优先考虑将一个类设置成不变类。
在对其他类的引用上,将引用其他对象的次数降到最低。
不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。
谨慎使用序列化(Serializable)功能。

//迪米特法则/最少知识原则
public class LODTest {
    public static void main(String[] args) {
        //我要买个手机才能读书
        new OldMe().read(new Phone());
        new NewMe().read(new PhoneII(), "ONE DAY");
    }

    //我自己要找到这本书再打开
    static class OldMe {
        Book book;

        void read(Phone phone) {
            book = new Book("ONE DAY");
            phone.readBook(book);
        }
    }

    //上层交互类,直接被调用的类
    static class Phone {
        void readBook(Book book) {
            new ReaderAPP().openBook(book);
        }
    }

    //app 功能类
    static class ReaderAPP {
        void openBook(Book book) {
            System.out.println("book's name is " + book.getName());
        }
    }

    //最底层数据类
    static class Book {
        String name;

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

        public String getName() {
            return name;
        }
    }

 //    ---------------------------------------------------------------------------------
//    我告诉手机我想看书,并且告诉书名,就应该可以直接开始看
    static class NewMe {
        void read(PhoneII phone, String bookName) {
            phone.readBook(bookName);
        }

    }

    static class PhoneII {
        //我也应该只要打开app,告诉他书名就不管了
        ReaderAPPII app;

        void readBook(String bookName) {
            app = new ReaderAPPII();
            app.read(bookName);
        }
    }

    static class ReaderAPPII {
        Book book;

        void read(String bookName) {
            book = new Book(bookName);
            System.out.println("book's name is " + book.getName());
        }
    }

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

推荐阅读更多精彩内容