栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Java 常用的设计模式】

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Java 常用的设计模式】

目录

前言

一、设计原则

1.1 开闭原则

1.2 单一职责原则

1.3 依赖倒置原则

1.4 接口分离原则

1.5 迪米特法则

1.6 里氏替换原则

二、设计模式

2.1 单例模式

2.1.1 饿汉式

2.1.2 懒汉式非安全

2.1.3 懒汉式安全

2.1.4 double+check

2.1.5 静态内部类

2.1.6 枚举

2.2 建造者模式

2.3 适配器模式

2.4 桥接模式

2.5 装饰器模式

2.6 责任链模式

 2.7 模板模式

总结


前言

        合理的使用设计模式可以简化开发,提高代码的阅读量,让代码看起来更加的精简,代码结构层次更加的清晰,学习设计模式可以让我们的思维更加的灵活和抽象化。

        代码中从不使用设计模式的缺点是:代码看起来繁杂、凌乱、臃肿和代码占用大小增加,阅读性差,找不到阅读入口等等。

        但是如果不熟悉设计模式,没有深入的研究过,不了解它的核心思想,生搬硬套的使用设计模式,也会出现线程安全,资源泄露和代码性能降低等等问题。

        这篇文章就是以我的理解对常用的设计模式进行讲解,帮助读者快速的了解这些设计模式,但是怎么使用它,还是要看具体的场景。


一、设计原则

        简单的介绍一下六大设计原则,因为设计模式离不开这些原则。

1.1 开闭原则

        对外扩展开发,对内修改关闭。

        如:一个人单身男每天必须要吃早餐,而且就两样鸡蛋和牛奶,其他啥也不吃。

public class Person {

    public void eatBreakFast(){
        System.out.println("吃鸡蛋");
        System.out.println("喝牛奶");
    }

}

         假如有一天他找到女朋友了,女朋友说:你必须要吃面包。(女朋友的话必须听,不能反驳)

        这个时候在不满足开闭原则的话,是下面的样子。

public class Person {

    public void eatBreakFast(){
        System.out.println("吃鸡蛋");
        System.out.println("喝牛奶");
        System.out.println("吃面包");
    }

}

        那么满足开闭原则的话是这样的。

public class Person {

    public void eatBreakFast(){
        System.out.println("吃鸡蛋");
        System.out.println("喝牛奶");
    }

    public void eatBreakFastOfHasGirlFriend(){
        System.out.println("吃鸡蛋");
        System.out.println("喝牛奶");
        System.out.println("吃面包");
    }
    
}

        这样一来,我们不改变之前的逻辑和功能,只对它进行扩展。调用者只需要调用新的方法就行了。 这样有一天调用者想调用之前的方法,只需要换个方法名就行了。(如果那一天他失恋了,没有女朋友了,他还可以按照之前的方式吃早餐。。。。。他应该很开心吧。。。。。。)

1.2 单一职责原则

        一个类、接口或者方法只允许有一个职责。

        用方法来说明,假设一个方法就是一个人。

        如果不满足单一职责原则,是这样的。

public class Person {

    public void person(){
        System.out.println("我是一名电工,会修电,我有相关证书");
        System.out.println("我是一名厨师,会做饭,我有相关证书");
        System.out.println("我是一名教师,会教书,我有相关证书");
        System.out.println("我是一名医生,会看病,我有相关证书");
    }

}

         我们为了不让这个方法(人)臃肿(累死),所以单一职责原则出现了。

public class Person {

    public void person1(){
        System.out.println("我是一名电工,会修电,我有相关证书");
    }
    public void person2(){
        System.out.println("我是一名厨师,会做饭,我有相关证书");
    }
    public void person3(){
        System.out.println("我是一名教师,会教书,我有相关证书");
    }
    public void person4(){
        System.out.println("我是一名医生,会看病,我有相关证书");
    }

}

        单一职责的原理就是,为了在有一天要变更某一个功能时,变动的地方更小,只涉及某一个功能。(假设这个人很厉害,辛辛苦苦到80岁,终于所有证书都有了,都可以合法做这些事挣钱养家了,某一天接到通知,所有的证书要重新考试,问:此时他的心理阴影面。。。。。。。。) 

1.3 依赖倒置原则

        依赖抽象而不是依赖实现。抽象不应该依赖细节,细节应该依赖抽象。高层模块不能依赖低层模块,二者都应该依赖抽象。

        假如不满足依赖倒置原则,喜羊羊吃草是这样的。

// 小草
public interface Grass {
    void grassType();
}
// 红颜色的小草
public class RedGrass implements Grass{
    @Override
    public void grassType() {
        System.out.println("我是红颜色的小草,来吃我吧");
    }
}
// 绿颜色的小草
public class GreenGrass implements Grass{
    @Override
    public void grassType() {
        System.out.println("我是绿颜色的小草,来吃我吧");
    }
}

// 测试代码
public class Test {
    // 红色的草
    static RedGrass redGrass;

    public Test(RedGrass redGrass) {
        this.redGrass = redGrass;
    }

    public static void main(String[] args) {
            
        new Test(new RedGrass());
        System.out.println("我是喜羊羊,我要吃草");
        redGrass.grassType();

    }

}

        假如有一天,这个世界上没有红色的草,那么喜羊羊就没了。。。。。,满足依赖倒置原则时,是这样的。

public class Test {
    // 是草就行
    static Grass grass;

    public Test(Grass grass) {
        this.grass = grass;
    }

    public static void main(String[] args) {

        new Test(new RedGrass());
        System.out.println("我是喜羊羊,我要吃草");
        grass.grassType();
        
        new Test(new GreenGrass());
        System.out.println("我是喜羊羊,我要吃草");
        grass.grassType();

    }

}

        这样一来,不知道你们有没有明白依赖倒置原则的思想,反正喜羊羊是不会饿死的,是个草它就可以吃。。。。。。。。

1.4 接口分离原则

        采用多个与特定客户类有关的接口比采用一个通用的接口要好。

        假如一个有女朋友的人,他女朋友一星期,每一天要穿不同的衣服,这些衣服都要他提前准备好。不满足接口分离原则的时候是这样。

public class Boy implements Clothes{
    public void getClothes(String date){
        if (date.equals("星期一")){
            System.out.println("今天你穿:牛仔裤搭配高跟鞋");
        } else if (date.equals("星期二")){
            System.out.println("今天你穿:牛仔裤搭配运动鞋");
        }else if (date.equals("星期三")){
            System.out.println("今天你穿:牛仔裤搭配帆布鞋");
        }else if (date.equals("星期四")){
            System.out.println("今天你穿:裙子搭配高跟鞋");
        }else if (date.equals("星期五")){
            System.out.println("今天你穿:裙子搭配运动鞋");
        }else if (date.equals("星期六")){
            System.out.println("今天你穿:裙子搭配帆布鞋");
        }else if (date.equals("星期七")){
            System.out.println("今天你穿:九分裤搭配运动鞋");
        }
    }
}

        使用接口分离原则是这样的。

public class Boy implements Clothes{
    @Override
    public void getMondayClothes(String date) {
        System.out.println("今天你穿:牛仔裤搭配高跟鞋");
    }

    @Override
    public void getTuesdayClothes(String date) {
        System.out.println("今天你穿:牛仔裤搭配运动鞋");
    }

    @Override
    public void getWednesdayClothes(String date) {
        System.out.println("今天你穿:牛仔裤搭配帆布鞋");
    }

    @Override
    public void getThuresdayClothes(String date) {
        System.out.println("今天你穿:裙子搭配高跟鞋");
    }

    @Override
    public void getFridayClothes(String date) {
        System.out.println("今天你穿:裙子搭配运动鞋");
    }

    @Override
    public void getSaturdayClothes(String date) {
        System.out.println("今天你穿:裙子搭配帆布鞋");
    }

    @Override
    public void getSundayClothes(String date) {
        System.out.println("今天你穿:九分裤搭配运动鞋");
    }
}

1.5 迪米特法则

        一个类对于其他类知道的越少越好。一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。

public class Wolf {
    public static String name = "灰太狼";
}

public class Test {

    private String name = "喜羊羊";

    public static void main(String[] args) {

        System.out.println("我是" + name + ",小灰灰的爸爸是:" + Wolf.name);

    }

}

         不满足迪米特法则,那么喜羊羊就可以知道小灰灰的爸爸是谁,灰太狼不想让它的名字被别的羊知道,就要用满足迪米特法则。

public class Wolf {
     private static String name = "灰太狼";
}

public class Test {

    private String name = "喜羊羊";

    public static void main(String[] args) {
        //得不到Wolf.name
        System.out.println("我是" + name + ",小灰灰的爸爸是:" + Wolf.name);

    }

}

1.6 里氏替换原则

        派生类(子类)对象可以在程式中代替其基类(超类)对象,但是不能重写父类的非抽象方法。

        这个就是多态的使用,不用讲解了。


二、设计模式

2.1 单例模式

        属于创建型模式,它提供了一种创建对象的最佳方式。满足以下三点:

        单例类只能有一个实例。

        单例类必须自己创建自己的唯一实例。

        单例类必须给所有其他对象提供这一实例。

2.1.1 饿汉式
public class Singleton {

    private Singleton() {}

    private static Singleton singleton= new Singleton();

    public static Singleton getSingleton(){
        return singleton;
    }
    
}

2.1.2 懒汉式非安全
public class Singleton {

    private static Singleton singleton;

    private Singleton (){}
    
    public static Singleton getInstance() {
        // 多线程并发到这时,不能保证单例,所以不安全
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }

}

2.1.3 懒汉式安全
public class Singleton {

    private static Singleton singleton;

    private Singleton (){}

    // 安全是安全了,可以高并发都在这阻塞的话,降低性能
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }

}

2.1.4 double+check
public class Singleton {

    private volatile static Singleton singleton;

    private Singleton (){}
    
    public static Singleton getSingleton() {
        // 为空时才抢锁创建
        if (singleton == null) {
            // 加锁
            synchronized (Singleton.class) {
                // 再次判断,如果抢到锁发现已经不为空,证明之前抢到锁的已经创建了
                if (singleton == null) {
                    // 没有的话就创建一个
                    singleton = new Singleton();
                }
            }
        }
        // 直接返回
        return singleton;
    }

}

2.1.5 静态内部类
public class Singleton {

    private static class SingletonHolder {
        private static final Singleton SINGLETON = new Singleton();
    }
    
    private Singleton (){}
    
    public static final Singleton getInstance() {
        return SingletonHolder.SINGLETON;
    }

}

2.1.6 枚举
public enum Singleton {
    
    SINGLETON;
    
    public void doooooo() {
        //.........
    }

}

public class Test {
    
    public static void main(String[] args) {
        
        Singleton.SINGLETON.doooooo();
        
    }

}

         根据使用什么类型的单例,还是要结合业务和实际的需要。

2.2 建造者模式

        使用多个简单的对象一步一步构建成一个复杂的对象。属于创建型模式

//阳台
public class Balcony {
}
// 客厅
public class DrawingRoom {
}
// 书房
public class Study {
}
// 卫生间
public class Toilet {
}

// 构建一个房子,按照不同人的爱好
public class Room {

    // 阳台
    private Balcony balcony;
    // 客厅
    private DrawingRoom drawingRoom;
    // 书房
    private Study study;
    // 卫生间
    private Toilet Toilet;
    
    public Room(RoomFactory.Builder builder) {
        this.balcony = builder.balcony;
        this.drawingRoom = builder.drawingRoom;
        this.study = builder.study;
        this.Toilet = builder.Toilet;
    }
    
}
public class RoomFactory {

    private RoomFactory() {}
    // 内部的工具类
    public static class Builder{
        // 阳台
        public Balcony balcony;
        // 客厅
        public DrawingRoom drawingRoom;
        // 书房
        public Study study;
        // 卫生间
        public Toilet Toilet;

        public Builder builderBalcony(Balcony balcony) {
            this.balcony = balcony;
            return this;
        }

        public Builder builderDrawingRoom(DrawingRoom drawingRoom) {
            this.drawingRoom = drawingRoom;
            return this;
        }

        public Builder builderStudy(Study study) {
            this.study = study;
            return this;
        }

        public Builder builderToilet(builder.Toilet toilet) {
            Toilet = toilet;
            return this;
        }
        // 构建房子
        public Room build(){
            return new Room(this);
        }

        private Builder() {}
    }
    // 对外入口
    public static RoomFactory.Builder builder(){
        return new Builder();
    }

}

        构建两个不同设计的房子

public class Test {

    public static void main(String[] args) {
        Balcony balcony = new Balcony();
        DrawingRoom drawingRoom = new DrawingRoom();
        Study study = new Study();
        Toilet toilet = new Toilet();
        Room room1= RoomFactory.builder().builderBalcony(balcony).builderStudy(study).build();
        Room room2= RoomFactory.builder().builderToilet(toilet).builderDrawingRoom(drawingRoom).build();
    }

}

2.3 适配器模式

        两个不兼容的接口之间的桥梁。属于结构型模式

        假设现在的播放器只支持MP4格式,不支持其他格式。

public interface Video {

    void play(String format);

}

public class CommonVideo implements Video{
    @Override
    public void play(String format) {

        if (format.equals("MP4")){
            System.out.println("播放MP4格式视频");
        }else {
            System.out.println("不支持的播放格式");
        }
    }
}

        如果我们要进行升级,让它支持更多的格式,可以使用适配器模式。

// 定义高级视频播放器
public interface AdvancedVideo {

    void playAVI();
    void playWMV();
    void playRM();

}

public class AVIAdvancedVideo implements AdvancedVideo{
    @Override
    public void playAVI() {
        System.out.println("播放AVI格式视频");
    }

    @Override
    public void playWMV() {

    }

    @Override
    public void playRM() {

    }
}

public class WMVAdvancedVideo implements AdvancedVideo{
    @Override
    public void playAVI() {

    }

    @Override
    public void playWMV() {
        System.out.println("播放WMV格式视频");
    }

    @Override
    public void playRM() {

    }
}

public class RMAdvancedVideo implements AdvancedVideo{
    @Override
    public void playAVI() {

    }

    @Override
    public void playWMV() {

    }

    @Override
    public void playRM() {
        System.out.println("播放RM格式视频");
    }
}

// 定义适配器
public class VideoAdapter implements Video{

    private AdvancedVideo advancedVideo;

    public VideoAdapter(String format) {
        if (format.equals("AVI")){
            this.advancedVideo = new AVIAdvancedVideo();
        }
        else if (format.equals("WMV")){
            this.advancedVideo = new WMVAdvancedVideo();
        }
        else if (format.equals("RM")){
            this.advancedVideo = new RMAdvancedVideo();
        }else {
            // 按照业务进行不同处理
        }

    }

    @Override
    public void play(String format) {
        if (format.equals("AVI")){
            advancedVideo.playAVI();
        }else if (format.equals("WMV")){
            advancedVideo.playWMV();
        }else if (format.equals("RM")){
            advancedVideo.playRM();
        }else {
            // 按照业务进行不同处理
        }
    }
}

// 基础播放器支持其他格式
public class CommonVideo implements Video{
    @Override
    public void play(String format) {

        if (format.equals("MP4")){
            System.out.println("播放MP4格式视频");
        }else if (format.equals("AVI") || format.equals("WMV") || format.equals("RM")){
            new VideoAdapter(format).play(format);
        }else {
            System.out.println("不支持的播放格式");
        }
    }

    public static void main(String[] args) {
        CommonVideo commonVideo = new CommonVideo();
        commonVideo.play("MP4");
        commonVideo.play("AVI");
        commonVideo.play("WMV");
        commonVideo.play("RM");
    }
}

        它的缺点也很明显,如果新增播放格式,要修改很多类。

2.4 桥接模式

        抽象化与实现化解耦,使得二者可以独立变化。属于结构型模式

public interface Person {
    void doSomething();
}

public class Programmer implements Person{
    @Override
    public void doSomething() {
        System.out.println("我是程序员,我会写代码");
    }
}

public class Accountant implements Person {
    @Override
    public void doSomething() {
        System.out.println("我是会计,我会统计财务消息");
    }
}

// 对外的对象,提供调用者
public abstract class Worker {
    
    protected Person person;

    public Worker(BridgePattern.Person per) {
        this.person = per;
    }

    public abstract void doSome();
    
}

// 桥接对象
public class PersonBridge extends Worker{

    public PersonBridge(BridgePattern.Person per) {
        super(per);
    }

    @Override
    public void doSome() {
        person.doSomething();
    }

}


public class Test {
    public static void main(String[] args) {
        // PersonBridge只依赖抽象的Person,不管实现者是谁
        Worker accountant = new PersonBridge(new Accountant());
        accountant.doSome();
        Worker programmer = new PersonBridge(new Programmer());
        programmer.doSome();

    }
}

2.5 装饰器模式

        允许向一个现有的对象添加新的功能,同时又不改变其结构。属于结构型模式

        对一个普通的火锅进行不同的装饰。

// 火锅
public interface HotPot {

    void dooo();

}

public class baseHotPot implements HotPot{
    @Override
    public void dooo() {
        System.out.println("来个底料");
    }
}

public class Lettuce implements HotPot {

    private HotPot hotPot;

    public Lettuce(HotPot hotPot) {
        this.hotPot = hotPot;
    }

    @Override
    public void dooo() {
        hotPot.dooo();
        System.out.println("要一斤生菜");
    }
}

public class onion implements HotPot {

    private HotPot hotPot;

    public onion(HotPot hotPot) {
        this.hotPot = hotPot;
    }

    @Override
    public void dooo() {
        hotPot.dooo();
        System.out.println("要一斤洋葱");
    }
}

public class Garlic implements HotPot {

    private HotPot hotPot;

    public Garlic(HotPot hotPot) {
        this.hotPot = hotPot;
    }

    @Override
    public void dooo() {
        hotPot.dooo();
        System.out.println("要一斤蒜");
    }
}
public class Test {

    public static void main(String[] args) {

        // 只要火锅底料
        HotPot baseHotPot = new baseHotPot();
        baseHotPot.dooo();
        System.out.println();

        // 要火锅底料+蒜
        HotPot garlic = new Garlic(baseHotPot);
        garlic.dooo();
        System.out.println();

        // 要火锅底料+蒜+生菜
        HotPot lettuce = new Lettuce(garlic);
        lettuce.dooo();
        System.out.println();

        // 要火锅底料+生菜+洋葱
        HotPot lettuce1 = new Lettuce(baseHotPot);
        HotPot onion = new onion(lettuce1);
        onion.dooo();
    }

}

// 输出
来个底料

来个底料
要一斤蒜

来个底料
要一斤蒜
要一斤生菜

来个底料
要一斤生菜
要一斤洋葱

2.6 责任链模式

        为请求创建了一个接收者对象的链。 属于行为型模式

public interface Teacher {

    void correct(String job);

}

public class MathTeacher implements Teacher{
    @Override
    public void correct(String job) {
        if (job.contains("数学作业")){
            System.out.println("我是数学老师,批改数学作业");
        }
    }
}

public class ChineseTeacher implements Teacher{
    @Override
    public void correct(String job) {
        if (job.contains("语文作业")){
            System.out.println("我是语文老师,批改语文作业");
        }
    }
}

public class PhysicsTeacher implements Teacher{
    @Override
    public void correct(String job) {
        if (job.contains("物理作业")){
            System.out.println("我是物理老师,批改物理作业");
        }
    }
}

public class HistoryTeacher implements Teacher{
    @Override
    public void correct(String job) {
        if (job.contains("历史作业")){
            System.out.println("我是历史老师,批改历史作业");
        }
    }
}
public class TeacherChain {

    private static ArrayList teachers;
    static {
        teachers = new ArrayList<>();
        teachers.add(new HistoryTeacher());
        teachers.add(new MathTeacher());
        teachers.add(new ChineseTeacher());
        teachers.add(new PhysicsTeacher());
    }
    public static void correctJob(String job){
        for (Teacher teacher : teachers){
            teacher.correct(job);
        }
    }
}

public class Test {

    public static void main(String[] args) {
        TeacherChain.correctJob("数学作业|语文作业");
        System.out.println();
        TeacherChain.correctJob("数学作业|历史作业|物理作业");
    }

}

我是数学老师,批改数学作业
我是语文老师,批改语文作业

我是历史老师,批改历史作业
我是数学老师,批改数学作业
我是物理老师,批改物理作业

 2.7 模板模式

        一个抽象类公开定义了执行它的方法的方式/模板。属于行为型模式

public abstract class Person {

    // 模板方法
    protected void eat(){
        System.out.println("吃饭");
    }

    protected abstract void doooo();

}

public class Teacher extends Person {
    @Override
    protected void doooo() {
        System.out.println("上课");
    }
}

public class Student extends Person {
    @Override
    protected void doooo() {
        System.out.println("学习");
    }
}

public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        student.eat(); // 公共的行为,可以共享,提供一个模板
        student.doooo();

        Teacher teacher = new Teacher();
        teacher.eat(); // 公共的行为,可以共享,提供一个模板
        teacher.doooo();
    }
}

        提供一个模板,可以共用。


总结

       一起进步,一起写出更优秀的代码。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/785140.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号