常见设计模式
• 创建型模式: – 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。
• 结构型模式: – 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模 式 。
• 行为型模式: – 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模 式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
一:单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
• 核心作用: – 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
• 常见应用场景:
– Application 也是单例的典型应用(Servlet编程中会涉及到)
– 在Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理
– 在servlet编程中,每个Servlet也是单例
• 单例模式的优点: – 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要 比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动 时直接产生一个单例对象,然后永久驻留内存的方式来解决 – 单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计 一个单例类,负责所有数据表的映射处理
常见的五种单例模式实现方式:
– 主要: • 饿汉式(线程安全,调用效率高。 但是,不能延时加载。)
• 懒汉式(线程安全,调用效率不高。 但是,可以延时加载。)
– 其他: • 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用)
• 静态内部类式(线程安全,调用效率高。 但是,可以延时加载)
• 枚举单例(线程安全,调用效率高,不能延时加载)
• 饿汉式实现(单例对象立即加载)
public class SingletonDemo02 {
private static /*final*/ SingletonDemo02 s = new SingletonDemo02();
private SingletonDemo02(){} //私有化构造器
public static /*synchronized*/ SingletonDemo02 getInstance(){
return s; }}
public class Client {
public static void main(String[] args) {
SingletonDemo02 s = SingletonDemo02.getInstance();
SingletonDemo02 s2 = SingletonDemo02.getInstance();
System.out.println(s==s2); //结果为true } }
• 饿汉式单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问 题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。因此,可以省略synchronized关键字。
• 问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费!
• 懒汉式实现(单例对象延迟加载)
public class SingletonDemo01 {
private static SingletonDemo01 s;
private SingletonDemo01(){} //私有化构造器
public static synchronized SingletonDemo01 getInstance(){
if(s==null){
s = new SingletonDemo01(); }
return s; }
}
• 要点: – lazy load! 延迟加载, 懒加载! 真正用的时候才加载!
• 问题: – 资源利用率高了。但是,每次调用getInstance()方法都要同步,并发 效率较低。
• 如何选用?
– 单例对象 占用 资源 少,不需要 延时加载: • 枚举式 好于 饿汉式
– 单例对象 占用 资源 大,需要 延时加载: • 静态内部类式 好于 懒汉式
*二:工厂模式
– 实现了创建者和调用者的分离。
– 详细分类: • 简单工厂模式 • 工厂方法模式 • 抽象工厂模式
• 核心本质: – 实例化对象,用工厂方法代替new操作。
– 将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实 现类解耦。
• 工厂模式:
– 简单工厂模式 • 用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已 有代码)
– 工厂方法模式 • 用来生产同一等级结构中的固定产品。(支持增加任意产品)
– 抽象工厂模式 • 用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持 增加产品族)
• 应用场景 – JDK中Calendar的getInstance方法 – JDBC中Connection对象的获取
– Hibernate中SessionFactory创建Session
– spring中IOC容器创建管理bean对象
– XML解析时的DocumentBuilderFactory创建解析器对象
– 反射中Class对象的newInstance()
• 不使用简单工厂的情况
public class Client01 { //调用者
public static void main(String[] args) {
Car c1 = new Audi();
Car c2 = new Byd();
c1.run();
c2.run();
} }
– (1)简单工厂模式也叫静态工厂模式:
就是工厂类一般是使用静态方法, 通过接收的参数的不同来返回不同的对象实例。
– 对于增加新产品无能为力!不修改代码的话,是无法扩展的。
public class ComputerFactory {
public static Computer createComputer(String type){
Computer mComputer=null;
switch (type) {
case "lenovo":
mComputer=new LenovoComputer();
break;
case "hp":
mComputer=new HpComputer();
break;
case "asus":
mComputer=new AsusComputer();
break;
}
return mComputer;
}
}
public class CreatComputer {
public static void main(String[]args){
ComputerFactory.createComputer("hp").start();
}
}
3 优点和缺点
3.1 优点
工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
3.2 缺点
由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,同样破坏了“开闭原则”;在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
4 适用环境
在以下情况下可以使用简单工厂模式:
工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
(2)• 工厂方法模式要点: – 为了避免简单工厂模式的缺点,不完全满足OCP。
– 工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目 或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。
(3) 抽象工厂模式 – 用来生产不同产品族的全部产品。(对于增加新的产品,无能为力; 支持增加产品族) – 抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务 分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
三 :适配器模式
特点:
适配器继承或依赖已有的对象,实现想要的目标接口
消除由于接口不匹配所造成的类的兼容性问题
类的适配器模式、对象的适配器模式、接口的适配器模式
提高了类的复用,增加了类的透明度
(1)类的适配器模式
通过实现目标接口,继承原有类,在原有类的基础上增加接口中方法,将一个类转换成满足另一个新接口的类
Original.java
public class Original {
public void show(){
Log.i("msg", "This is Original");
}
}
ExpandInterfacen .java
public interface ExpandInterfacen {
void show();
void hide();
}
NewAdapter .java
public class NewAdapter extends Original implements ExpandInterfacen {
@Override
public void hide() {
Log.i("msg", "This is NewAdapter");
}
}
使用如下
public void onClick(View view){
NewAdapter adapter = new NewAdapter();
adapter.hide();
adapter.show();
}
(2)对象的适配器模式
不继承原有类,而是持有该类实例来实现兼容,将一个对象转换成满足另一个新接口的对象
ObjectAdapter.java
public class ObjectAdapter implements ExpandInterfacen {
private Original mOriginal;
public ObjectAdapter (){
mOriginal = new Original();
}
@Override
public void show() {
mOriginal.show();
}
@Override
public void hide() {
Log.i("msg", "This is ObjectAdapter");
}
}
使用如下
ObjectAdapter adapter = new ObjectAdapter();
adapter.show();
adapter.hide();
(3)接口的适配器模式
不希望实现一个接口中所有的方法,可选择一个抽象类实现接口,然后继承该抽象类实现想实现的方法即可
ExpandInterfacen.java
public interface ExpandInterfacen {
void show();
void hide();
void close();
void open();
}
AbstractInterface.java
public abstract class AbstractInterface implements ExpandInterfacen {
@Override
public void show() {
}
@Override
public void hide() {
}
@Override
public void close() {
}
@Override
public void open() {
}
}
Expand.java
public class Expand extends AbstractInterface {
@Override
public void show() {
super.show();
}
@Override
public void close() {
super.close();
}
}