2022-11-16

设计模式简介

设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。

设计原则

  • 对接口编程而不是对实现编程。
  • 优先使用对象组合而不是继承。

设计模式的类型

这些模式可以分为三大类:创建型模式、结构型模式、行为型模式

设计模式的六大原则

1、开闭原则:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。

2、里氏代换原则:任何基类可以出现的地方,子类一定可以出现。

3、依赖倒转原则:针对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则:使用多个隔离的接口,比使用单个接口要好。降低类之间的耦合度。

5、迪米特法则,又称最少知道原则:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则:尽量使用合成/聚合的方式,而不是使用继承。

1、工厂模式

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类。

优点:

1、一个调用者想创建一个对象,只要知道其名称就可以了。

2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景:1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

实现

步骤 1

创建一个接口:

public interface Shape {
   void draw();
}

步骤 2

创建实现接口的实体类。

public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

步骤 3

创建一个工厂,生成基于给定信息的实体类的对象。

public class ShapeFactory {
    
   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
}

步骤 4

使用该工厂,通过传递类型信息来获取实体类的对象。

public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
 
      //获取 Circle 的对象,并调用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");
 
      //调用 Circle 的 draw 方法
      shape1.draw();
 
      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
 
      //调用 Rectangle 的 draw 方法
      shape2.draw();
 
      //获取 Square 的对象,并调用它的 draw 方法
      Shape shape3 = shapeFactory.getShape("SQUARE");
 
      //调用 Square 的 draw 方法
      shape3.draw();
   }
}

步骤 5

执行程序,输出结果:

Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.

2、单例模式

单例模式具有典型的三个特点:

  • 只有一个实例。
  • 自我实例化。
  • 提供全局访问点。

单例设计模式的优缺点:

优点:

1、由于单例模式只生成了一个实例,所以能够节约系统资源,减少性能开销,提高系统效率,

2、避免频繁的创建销毁对象,可以提高性能;

3、避免对共享资源的多重占用,简化访问;

4、为整个系统提供唯一一个全局访问点,能够严格控制客户对它的访问。

缺点:

1、不适用于变化频繁的对象;

2、也正是因为系统中只有一个实例,这样就导致了单例类的职责过重,违背了“单一职责原则”,

滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;

3、同时也没有抽象类,这样扩展起来有一定的困难。

4、如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失;

单例模式的应用场景:

场景一:

windows的任务管理器,无论你点击多少次,始终都只有一个管理器窗口存在,系统并不会为你创建新的窗口,整个系统运行的过程中,系统只维护了一个进程管理器的实例。

场景二:

线程池、数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,用单例模式来维护,就可以大大降低这种损耗。

场景三:

程序的日志模块。一般也是采用单例模式实现。由于共享的日志文件一直处于打开状态,只能有一个实例去操作,否则内容不好追加。 采用单例模式就可以。

场景四:

在我们的实际项目开发中,可以使用单例模式来封装一些常用的工具类,保证整个应用常用的数据统一。或者保存一些共享数据在内存中,其他类随时可以读取。

单例设计模式的两种方法:

懒汉式(类加载时并没有生成实例,只有在第一次调用getInstance的时候才生成实例化)

加入volatilesynchronized 可以保证线程安全,但是会影响性能;如果不加volatilesynchronized会存在线程安全问题,这是懒汉式单例的缺点。

优化后,双重检查(推荐使用):

// 懒汉式(线程安全,同步方法)
public class Singleton {
    private static volatile Singleton instance;//对象属性前应使用volatile修饰,防止指令重排带来的同步问题
    
    private Singleton() {}
    
    //提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
    //同时保证了效率, 推荐使用
    public static Singleton getInstance() {
        if(instance == null) {
            synchronized (Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
            
        }
        return instance;
    }
}

避免了资源的浪费;

提升了效率

防止了反射破坏

饿汉式(类加载的时候就开始生成实例,保证在调用getInstance的时候已经存在实例)

public class HungrySingleton
    {
        private static final HungrySingleton instance=new HungrySingleton();
        private HungrySingleton(){}
        public static HungrySingleton getInstance()
        {
            return instance;
        }
    }
  • 优点:这种写法在类加载的时候就可以完成对象的实例化,避免了线程同步的问题
  • 缺点:类装载就完成实例化,肯定会造成内存浪费问题

3、代理模式

在有些情况下,⼀个客户不能或者不想直接访问另⼀个对象,这时需要找⼀个中介帮忙完成某项任务,这个中介就是代理对象。

实现

4、适配器模式

在现实⽣活中,经常出现两个对象因接口不兼容而不能在⼀起工作的实例,这时需要第三者进行适配。

实现

5、策略模式

在现实生活中,常常遇到实现某种目标存在多种策略可供选择的情况。如:乘坐交通工具,有飞机、汽车、火车可供选择,但是只能选择一种。 在软件开发中也常常遇到类似的情况,当实现某⼀个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。这些策略之间是相互排斥、可替换的。并且是有一定的优先级顺序的。

实现

6、装饰器模式

现实生活中,一般情况下一个人换了一件衣服之后,我们依然可以认出他,衣服就是他的装饰,说明装饰并不影响一个人的容貌,也就是不影响这个人的功能,但是通过穿着一件高档外衣,却可以提升一个人的气质,这就是装饰的作用。装饰器模式就是通过装饰一个对象而不改变对象来让这个对象更强大。

实现

7、观察者模式

观察者模式,又叫做通知模式,是一种一对多的模式。现实中,当校长或者老师在台上发布一个命令的时候,广播喇叭就会将命令传达给每个学生,学生们听到命令的时候,都会有自己的反应。当一个对象被修改时,则会自动通知依赖它的对象。

实现

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

推荐阅读更多精彩内容

  • RTO前处理系统之大孔树脂吸附技术简介 一、树脂吸附工艺与RTO结合应用的场景 针对医化行业[https://hu...
    金沃泰科技李工阅读 141评论 0 0
  • 基础心理学第一次课 1、普通心理学,也叫科学心理学,是一门中间学科(科学)。科学心理学认为心理是脑的机能,是对客观...
    Diana_58d9阅读 188评论 0 0
  • HYTF系列变频串联谐振试验装置 产品概述 1.串联谐振试验装置:就是做耐压试验的设备,它是为了满足大容量的被试品...
    huayuan阅读 86评论 0 0
  • Nature | 细胞外流体粘度增强细胞迁移和癌症扩散 原创huacishu图灵基因2022-11-16 10:1...
    图灵基因阅读 256评论 0 0
  • 今天中午,我吃了一份香菇鸡肉粥、牛肉馅饼、一点猪肉水饺,北方的实物份量比南方大,最后还是剩下了3只水饺,浪费了有一...
    进击的2022年阅读 195评论 0 0