下面通过对spring源码的分析进行对spring中使用到的设计模式进行学习。
在设计模式中有23种设计模式,分别是创建型,结构型和行为型,这里借鉴了其他书籍和作者的观点进行学习,有错误的地方欢迎评论指正。
创建型
工厂方法模式(Factory Method)、抽象工厂模式(Abstract Factory)、
建造者模式(Builder)、原型模式(Prototype)、单例模式(Singleton)
结构型
适配器模式(Adapter)、桥接模式(Bridge)、组合模式(Composite)、
装饰器模式(Decorator)、门面模式(Facade)、享元模式(Flyweight)、
代理模式(Proxy)
行为型
解释器模式(Interpreter)、模板方法模式(Template Method)、
责任链模式(Chain of Responsibility)、命令模式(Command)、
迭代器模式(Iterator)、调解者模式(Mediator)、备忘录模式(Memento)、
观察者模式(Observer)、状态模式(State)、策略模式(Strategy)、
访问者模式(Visitor)
通常来说,设计模式都是混合使用,不会独立应用。利用穷举法充分理解设计模式的应用场景。在平时
的应用中,不是用设计模式去生搬硬套,而是根据具体业务问题需要时借鉴。
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原
则中说,任何基类可以出现的地方,子类一定可以出现。 LSP 是继承复用的基石,只有当衍生类可以
替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增
加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而
基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
这个是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,
从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。
所以上文中多次出现:降低依赖,降低耦合。
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能
模块相对独立。
原则是尽量使用合成/聚合的方式,而不是使用继承。
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节,对象的创建由相关的工厂来完成。就像我们去商场购买商品时,不需要知道商品是怎么生产出来一样,因为它们由专门的厂商生产。
应用场景:又叫做静态工厂方法(StaticFactory Method)模式,但不属于 23 种设计模式之一。
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。
Spring 中的 BeanFactory 就是简单工厂模式的体现,根据传入一个唯一的标识来获得 Bean 对象,但
是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。
首先有一个接口 Milk
public inteface Milk {
//这里是一个接口类
}
接着有它的实现类 Telunsu 和 Mengniu
public class Telunsu implements Milk {
public Telunsu() {
System.out.println("I am Telunsu");
}
}
public class Mengniu implements Milk {
public Mengniu() {
System.out.println("I am Mengniu");
}
}
然后创建一个简单的工厂
public class SimpleFactory {
public Milk GetMilk(String name) {
switch (name) {
case "Telunsu":
return new Telunsu();
case "Mengniu":
return new Mengniu();
}
return null;
}
}
接着就可以用工厂创建对象
public class FactoryTest {
@Test
public void testCreateMilk(){
SimpleFactory factory = new SimpleFactory();
//通过工厂创建一个特伦苏牛奶
Milk telunsu = factory.GetMilk("Telunsu");
//通过工厂创建一个蒙牛牛奶
Milk mengniu = factory.GetMilk("Mengniu");
}
}
输出结果
I am Telunsu
I am Mengniu
通过简单工厂可以通过名称获取到对应的类,但依然还需要一个唯一标识来获取类。
工厂方法(FactoryMethod)模式的定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。
我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背“开闭原则”。
本节介绍的“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
接着上面的例子,采用工厂方法的来进行创建对象
首先,需要一个工厂的抽象类
public interface Factory {
//专门用来生产牛奶
Milk GetMilk();
}
接着创建工厂实体
蒙牛工厂
public class MengNiuFactory implements Factory{
@Override
public Milk GetMilk() {
return new Mengniu();
}
}
特仑苏工厂
public class TelunsuFactory implements Factory {
@Override
public Milk GetMilk() {
return new Telunsu();
}
}
最后通过创建工厂来创建对象
@Test
public void testFunFactory(){
//创建蒙牛
Factory factory = new MengNiuFactory();
Milk mengNiu = factory.GetMilk();
//创建特仑苏
factory = new TelunsuFactory();
Milk telunsu = factory.GetMilk();
}
这样会不断的创建工厂,不用在创建唯一标识,但还是需要知道具体的工厂,下面将介绍抽象工厂
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
首先创建一个抽象工厂,专门用来生产各种牛奶
public abstract class AbstractFactory {
//创建蒙牛牛奶
public abstract Milk biuldMengNiu();
//创建特仑苏牛奶
public abstract Milk biuldTelunsu();
}
然后创建实现该工厂的功能
public class MilkFactory extends AbstractFactory {
@Override
public Milk biuldMengNiu() {
return new Mengniu();
}
@Override
public Milk biuldTelunsu() {
return new Telunsu();
}
}
最后通过工厂创建类
@Test
public void testAbstrFactory(){
MilkFactory milkFactory = new MilkFactory();
//创建蒙牛牛奶
Milk mengNiu = milkFactory.biuldMengNiu();
//创建特仑苏牛奶
Milk telusu = milkFactory.biuldTelunsu();
}
通过上面的简单例子能够很容易理解工厂模式
下面用PC电脑来举例,PC工厂生产 鼠标和键盘,有两个抽象产品 Mouse 和 Keybo
接着创建出各厂商的产品 鼠标 DellMouse和HpMouse ,键盘 DellKeybo 和 HpKeybo
然后创建各工厂,通过HpFactory创建出hp的鼠标和键盘,通过DellFactory生产出Dell的鼠标和键盘。
当有新的PC设备出现时,在抽象工厂中创建新的抽象产品,工厂实现就可以完成新产品的添加
抽象工厂模式用来解决接口选择的问题,系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。
注意事项:产品族难扩展,产品等级易扩展。
模式的应用场景:
抽象工厂模式最早的应用是用于创建属于不同操作系统的视窗构件。如 java 的 AWT 中的 Button 和 Text 等构件在 Windows 和 UNIX 中的本地实现是不同的。
抽象工厂模式通常适用于以下场景:
当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。
模式的扩展
抽象工厂模式的扩展有一定的“开闭原则”倾斜性:
当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。
另一方面,当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式。