工厂模式

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
定义
父类定义了创建对象的接口,但是由子类来具体实现,工厂方法让类把实例化的动作推迟到了子类当中。
优点
- 一个调用者想创建一个对象,只要知道其名称就可以了;
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以;
- 屏蔽产品的具体实现,调用者只关心产品的接口。
缺点
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。单例模式
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存);
-
使用场景
要求生产唯一序列号;
- WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来;
创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
分类
单例模式分为饿汉式和懒汉式,饿汉式指类加载时就初始化生成一个实例,而懒汉式在第一个请求时才生成一个实例。
实现方式
枚举
单例模式的最佳方法,它更简洁,自动支持序列化机制,绝对防止多次实例化。
JDK 版本:JDK1.5 起
是否 Lazy 初始化:否
是否多线程安全:是
实现难度:易public enum Singleton {INSTANCE;public Singleton getInstance(){return INSTANCE;}}
静态内部类
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:一般public class Singleton {private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private Singleton (){}public static final Singleton getInstance() {return SingletonHolder.INSTANCE;}}
饿汉式
public class Singleton {private static Singleton instance = new Singleton();private Singleton (){}public static Singleton getInstance() {return instance;}}
懒汉式
public class Singleton {private static Singleton instance;private Singleton (){}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}
模板模式
模板方法模式是一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤的实现方式。
观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
适配器模式
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。
意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
角色
- 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
- 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
- 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
实现
通过适配器类实现其要转换的方法,适配者继承或实现适配器类和目标接口。package adapter;//目标接口interface Target{public void request();}//适配者接口class Adapter{public void specificRequest(){System.out.println("适配者中的业务代码被调用!");}}//类适配器类class ClassAdapter extends Adapter implements Target{public void request(){specificRequest();}}//客户端代码public class ClassAdapterTest{public static void main(String[] args){System.out.println("类适配器模式测试:");Target target = new ClassAdapter();target.request();}}
应用
Arrays.asList()Arrays.asList()将数组转换为集合后,底层其实还是数组,不能对其使用修改集合的方法:add/remove/clear,这体现的是适配器模式,只是转换接口,后台的数据仍是数组。装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
装饰器通过一个父类来实现接口的所有方法,再通过一个子类继承父类(接口的所有方法在这里不是必须实现的了,父类相当于一个缓冲区),这样,子类就可以实现接口的某个方法,而无需强制实现所有接口方法。
优点
- 装饰模式与继承关系的目的都是要拓展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者“除掉”一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。
- 通过不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出更多不同行为的组合。
缺点
由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另外一方面,使用装饰模式会产生比使用继承关系所产生的更多的对象。而更多的对象会使得查找错误更为困难,特别是这些对象在看上去极为相似的时候。应用
装饰模式在Java语言中最著名的应用莫过于JAVA I/O标准库的设计了。
InputStream结构图
根据上图可以看出:
- 抽象构建角色(Component):由
InputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。 - 具体构件角色(ConcreteComponent):由
ByteArrayInputStream、FileInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口。 - 抽象装饰角色(Decorator):由
FilterInputStream、ObectInputStream等类扮演。它们实现了InputStream所规定的接口。 - 具体装饰角色(ConcreteDecorator):由几个类扮演,分别是
BufferedInputStream、DataInputStream以及两个不常用到的类LineNumberInputStream、PushbackInputStream。
