设计模式

http://c.biancheng.net/view/1322.html

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

一.创建型模式

创建型模式分为以下几种。

  • 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
  • 原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。
  • 工厂方法(FactoryMethod)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。
  • 抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。
  • 建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。

1.单例模式

(1)优点

单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:

1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。

2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。

3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。

(2)三要素

1、私有的构造方法

2、指向自己的私有静态引用

3、以自己实例为返回值的公有静态方法;

(3)分类

1、饿汉模式:在加载类的时候就已经初始化执行自己的引用,主动创建了实例,适用于多线程下。

2、懒汉模式:动态调用类的初始化方法,才创建实例,不适用与多线程下

(4)懒汉转饿汉的三种方式

1、synchronized修饰初始化方法

2、synchronized代码块的双重检测方法,注意指令重排问题

3、静态内部类

(5)适用场合

1、需要频繁的进行创建和销毁的对象;

2、创建对象时耗时过多或耗费资源过多,但又经常用到的对象;

3、工具类对象;

4、频繁访问数据库或文件的对象。

2.简单工厂模式

将“类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端代码中显式指定,实现了解耦。

(1)三要素(举栗子说明)

1、抽象产品类;面条抽象类{面条的描述方法}

2、具体产品类:具体面条类继承面条抽象类和重写面条描述方法,如重庆小面,山西刀削面,兰州拉面等等多个实现类

3、创建工厂类:根据传入的不同参数,使用静态创建方法,创建不同面条的实例;swith语句或者if语句判断

(2)优点

1、将创建实例的工作使用实例的工作分开,使用者不必关心类对象如何创建,实现了解耦;

2、把初始化实例时的工作放到工厂里进行,使代码更容易维护。 更符合面向对象的原则 & 面向接口编程,而不是面向实现编程。

(3)缺点

1、工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;

2、违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂。

3、简单工厂模式由于使用了静态工厂方法静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。

3.工厂方法

针对简单工厂存在的问题,提出改进的工厂方法。通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。

(1)四要素

1、抽象产品类;面条抽象类{面条的描述方法}

2、具体产品类:具体面条类继承面条抽象类和重写面条描述方法,如重庆小面,山西刀削面,兰州拉面等等多个实现类

3、抽象的工厂类:创建面条抽象类{抽象的创建面条方法}

4、具体创建工厂:具体的创建不同面条的类,继承抽象工厂方法,实现抽象类并实例化对应的面条;

(2)优点

1、更符合开-闭原则:新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可。简单工厂模式需要修改工厂类的判断逻辑

2、符合单一职责原则:每个具体工厂类只负责创建对应的产品。简单工厂中的工厂类存在复杂的switch逻辑判断

3、不使用静态工厂方法,可以形成基于继承的等级结构。

(3)缺点

1、添加新产品时(比如例子中的饮品),除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;

2、由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

3、虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;

4、一个具体工厂只能创建一种具体产品

4.抽象工厂

根据工厂方法中,只能创建一个具体产品的问题,提出的抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类;具体的工厂负责实现具体的产品实例。

(1)四要素

1、多个抽象产品类;面条抽象类{面条的描述方法},饮品抽象类{饮品的描述方法}

2、对应每个抽象方法类的具体产品类:具体面条类继承面条抽象类和重写面条描述方法,如重庆小面,山西刀削面,兰州拉面等等多个实现类,具体饮品类继承饮品抽象类和重写饮品描述方法,如可乐,雪碧,咖啡等等多个实现类,

3、工厂的实现类:工厂接口,包括面面条创建的抽象方法和饮品创建的抽象方法。

4、具体的创建工厂类:创建具体的工厂{重写的创建面条方法的方法和创建饮品的方法}

(2)优点

解决了每个工厂只能创建一类产品

(3)缺点

1、抽象工厂模式很难支持新种类产品的变化。
这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变,这样也就违背了“开发——封闭”原则。

5.建造者模式

隐藏创建对象的建造过程 & 细节,使得用户在不知对象的建造过程 & 细节的情况下,就可直接创建复杂的对象;

建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。

建造者(Builder)模式的主要角色如下:

  1. 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个滅部件。
  2. 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
  3. 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
  4. 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。

(1)优点

1、降低创建复杂对象的复杂度,方便用户创建复杂的对象(不需要知道实现过程)

2、隔离了创建对象的构建过程 & 表示,代码复用性 & 封装性(将对象构建过程和细节进行封装 & 复用)

举个栗子:

例子:造汽车 & 买汽车。

  1. 工厂(建造者模式):负责制造汽车(组装过程和细节在工厂内)
  2. 汽车购买者(用户):你只需要说出你需要的型号(对象的类型和内容),然后直接购买就可以使用了
    (不需要知道汽车是怎么组装的(车轮、车门、发动机、方向盘等等))

(2)缺点

1、建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

2、如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

6.原型模式

(1)使用场景:

1、通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式

2、就是java中的克隆技术,以某个对象为原型复制出新的对象 ,显然,新的对象具备原型对象的特点

(2)优点

效率高(直接克隆,避免了重新执行构造的过程步骤)。

克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值。克隆出的对象的属性值完全和原型对象相同,并且克隆出的新对象改变不会影响原型对象。然后,再修改克隆对象的值。

二.结构型模式

https://blog.csdn.net/wzy885588/article/details/77881470

结构型模式分为以下 7 种:

  1. 代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
  2. 适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
  3. 桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现的,从而降低了抽象和实现这两个可变维度的耦合度。
  4. 装饰(Decorator)模式:动态地给对象增加一些职责,即增加其额外的功能。
  5. 外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
  6. 享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。
  7. 组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。

1.装饰者模式:

动态的将新功能附加到对象上,在对象功能扩展方面,它比继承更有弹性。是一种组合和委托的思想,但是会导致设计中出现许多小类,如果过度使用,会让程序变得很复杂,难以看明白。

个人理解:装饰,就要有被装饰和装饰者两部分,是由于现在的功能增加了,但是根据开闭原则,不能在原来的类中改,只有新写一个,但是新的类也具有原来的功能,因此,这两个类要实现一个相同的接口并持有原来类的对象。

举个栗子:原来,有一个人接口,里面有吃饭这个抽象方法;有一个中国人这个实现类,实现类吃饭这个方法;但是要求,中国人吃饭前要先洗手(并不是所有人吃饭前都要先洗手的),所以写了一个类文明的中国,它要实现人这个接口,并调用中国人这个对象,在实现吃饭这个方法是,在里面首先写好洗手,再调用中国人对象的吃饭方法。就不用重写所有的吃饭内容了。

(1)设计原则

1、多用组合,少用继承

2、   类应设计的对扩展开放,对修改关闭。

2.代理模式:

代理模式就是多一个代理类出来,替原对象进行一些操作。一个类代表另一个类的功能。代理类就像中介,它比我们掌握着更多的信息。

举个栗子:买火车票不一定在火车站买,也可以去代售点。SpringAOP就是代理模式

(1)优点

 1、职责清晰。 2、高扩展性。 3、智能化。

(2)缺点

1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

3.适配器模式

适配器可以把某个类的接口转换成用户需要的另一个接口。举个栗子:手机充电器就是一个电压转换的接口。

(1)分类

1、接口适配器

接口转换器是针对有些接口中存在大量的抽象方法,但是实际应用中不需要那么多的方法,如果直接实现这个接口,就必须要实现它的所有抽象方法(即使是什么都不做,也要有空方法),这样就会不满足迪米特原则,因此可以通过一个抽象类,这个抽象类实现了接口的所有方法(空方法),这样再继承这个抽象类,进实现自己想要的方法即可。

2、类适配器

类适配器是为了兼容原有的类的方法,但又需要一些新的方法,这样就可以通过实现一个包含想要实现的方法的接口,再继承原有类,实现功能。

这里感觉类适配器和装饰者模式优点像,但是需要注意的是:

装饰者模式不需要继承原来的类,而且需要原类实现接口。在初始化时需要传入原来对象。

类适配器不要继承原来的类,并且不用原类实现接口;

3、对象适配器

对象适配器模式更像是类适配器模式的优化,因为如果按照类适配器的写法,由于java是单继承的,继承了该类就不能继承其他类了。有一定的局限性。而对象适配器模式呢,就是把适配器中对源类的操作,从继承关系,转换到了多态的方式实现。增加了扩展性。

它的写法与装饰者很像,通过对原来的类调用,方式,不需要继承,但不同的是,装饰模式调用的接口,并用原类来实现。

4.桥接模式

桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化。桥接的用意是:将抽象化与实现化解耦,使得二者可以独立变化,像我们常用的JDBC桥DriverManager一样,JDBC进行连接数据库的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不用动,原因就是JDBC提供统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了。

(1)优点:

1、抽象和实现的分离。 2、优秀的扩展能力。 

(2)缺点:

桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

5.外观模式

外观模式(Facade),他隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。这种类型的设计模式属于结构性模式。为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用。

6.享元模式

想一想软件开发中常见的字符串,一个文本字符串中往往存在很多重复的字符,如果每一个字符都用一个单独的对象来表示,将会占用较多的内存空间。 这时就可以通过享元模式实现相同或相似对象的重用。在逻辑上每一个出现的字符都有一个对象与之对应,然而在物理上它们却共享同一个享元对象,这个对象可以出现在一个字符串的不同地方,相同的字符对象都指向同一个实例。

7.组合模式

我们在电脑中找寻特定的文件的时候,其实是从一个父类元素一级一级向下查找的,这实际上是一个树形结构,树形结构就有叶节点和非叶节点,他们肯定具有不同的功能,可是很多时候我们希望能够没有区别地处理他们,这就是组合模式的动机。

组合模式的主要优点在于可以方便地对层次结构进行控制,客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关心自己处理的是单个对象还是整个组合结构,简化了客户端代码;其缺点在于使设计变得更加抽象,且增加新构件时可能会产生一些问题,而且很难对容器中的构件类型进行限制。

 

三.行为型模式

https://blog.csdn.net/AARON_YANG666/article/details/52900907

1.策略模式

但从名字来讲,策略模式就是针对多种可互相替代方案的一种选择策略

举个栗子:商场有活动,有现金满减和打折,所以选择不同的策略会有不同的结果。可能每一天的打折方式都不一样,我们不能每次都去重写打折类,这样就违背了开闭原则。因此,我们就可以针对打折抽象出一个接口,每一种打折方式都去实现这个接口,并重写打折逻辑。当然我们还需要一个打折管理器,在管理器类中根据传入的打折对象,返回正确的折后价。

功能上和工厂方法很是相同,这里说一下策略模式的优点

1、相对来说实现类比抽象工厂方法模式少,也就是工作量会小一点

2、从理解上来说,策略模式比抽象工厂方法更直接一点。工厂模式需要通过工厂类去创建需要的对象,而策略模式是用户自己创建后传入的。

2.观察者模式

观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。

3.访问者模式

访问者模式把数据结构和作用于结构上的操作解耦合,使得对数据操作可相对自由地演化。访问者模式适用于数据结构相对稳定,算法又易变化的系统。

因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。

4.迭代器模式

顾名思义,迭代器模式就是顺序访问聚集中的对象,一般来说,集合中非常常见,如果对集合类比较熟悉的话,理解本模式会十分轻松。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值