1.单例模式
一个类仅有一个实例,并提供它的全局访问点。
1.饿汉单例
线程安全,非Lazy Loading(延迟加载),类加载时就初始化。较为常用。
class Singleton
{
private static Singleton instance = new Singleton();//初始化可以放到static{}代码块中
private Singleton() {}
public static Singleton getInstance()
{ return instance; }
}
2.懒汉单例(非线程安全)
由于某种执行时序下可能执行返回两个new Singleton(),因此线程不安全。实现Lazy Loading。
class Singleton
{
private static Singleton instance =null;
private Singleton() {}
public static Singleton getInstance()
{ if(instance==null)
instance = new Singleton();
return instance; }
}
3.懒汉单例(线程安全)
通过对静态方法getInstance()添加类锁,完成同步。线程安全,实现Lazy Loading,但因为synchronized而使多线程运行时频繁阻塞,影响效率。
4.双检锁(DCL)
同样是添加类锁,但不对方法加锁,而使用synchronized代码块,对instance=null判断语句后的情况加类锁,然后再次进行判断(考虑到在第一个拿锁者实例化之前,其他线程进入也进入到该区域阻塞)。
5.静态内部类实现
写个静态内部类,在里边放个静态的外部类对象的实例。
6.枚举enum
支持自动序列化,线程安全,绝对防止多次实例化。
Singleton.Instance.set(5)这样来访问单例。
enum Singleton
{
Instance;
private int value;
public void set(int i) {value=i;}
}
2.工厂模式
1.简单工厂(Single Factory)模式
专门定义一个工厂类来(根据参数不同)创建其他类(产品)的实例。,被创建的实例通常拥有共同的父类。
缺点:增添一个新的产品生成类需要改动整个工厂类
class SingleFactory
{
public static Product createProduct(T t,……)
{
/**
* Product是抽象类或者接口,含有代表其作用的抽象函数func();
* Product1,2…是继承或者实现了Product,重写func()后的实现类,通过if-else分支来实例化与返回相应的对象
*/
if(exp1) return new Product1();
else if(exp2) return new Product2();
else if(exp3) return new Product3();
……
//调用SingleFactory.createProduct(参数),就可以完成对应对象的实例化,用的静态方法所以也叫静态工厂
}
}
2.多工厂方法
实际上是在简单工厂的基础上,将if-else的分支判断改成了多个static的方法。
即本来应该是单个静态方法传入参数,根据参数与分支条件来判断返回哪个实例。
现在变为多个写入多个返回不同Product子类对象的static方法,然后通过调用时选择方法来返回实例。
这样,增添修改对应的产品类实例时,就只需要在对应的静态方法中作修改。
3.工厂方法(Factory Method)模式
在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行
结构是,先定义一个工厂的接口,这个接口是需要返回产品的,接口有个抽象函数创建产品。
interface FactoryMethod
{
public Product createProduct();
}
然后再实现不同的子工厂类,这些工厂类重写createProduct()方法,返回相应的产品对象
class Factory1 implements FactoryMethod
{
public Product createProduct()
{ return new Product1(); }
}
class Factory2 implements FactoryMethod
{
public Product createProduct()
{ return new Product2(); }
}
……
和简单工厂比较,其实就是将if-else分支,变成了选择工厂类。我要产生产品1,那就:
FactoryMethod factory = new Factory1();
Product product = factory.createProduct();
评价:实际上和多方法工厂比较更合适,多工厂方法是在要添加修改产品类时,操作相应的静态方法。工厂方法则是操作相应的工厂类。产品类是两者都要修改的。工厂方法会在产品过多时,造成工厂类也很多的问题。
4.抽象工厂(Abstract Factory)
在工厂方法的基础上,由单产品系,变成了多产品系。
可以理解为其起作用的抽象方法createProduct()变成了createSizeOne()+createSizeTwo()+……
工厂方法的具体工厂类,本身有Product的单子类来决定。
抽象工厂则是从ProductSize1()里选一种,再从ProductSize2()里选一种,构成具体工厂。
interface AbstractFactory
{
public SizeOne createSizeOne();
public SizeTwo createSizeTwo();
……
}
class Factory1 implements AbstractFactory
{
/**
* 抽象类或者接口SizeOne代表某个产品线(平板),SizeOne1(ipad2),SizeOne2(ipadmini)……是这个产品的实现
* 抽象类或者接口SizeTwo代表另一个产品线(手机),SizeTwo1(iphone8),SizeOne2(iphoneX)……是这个产品的实现
*/
public SizeOne createSizeOne()
{ return new SizeOne1(); }
public SizeTwo createSizeTwo()
{ return new SizeTwo1(); }
//那么这个具体工厂Factory就是生产SizeOne1(ipad2)与SizeTwo1(iphone8)的工厂
}
3.适配器模式
将一个类的接口转换成客户端所需要的另一种接口。
主要适用于“望复用一些现存的类,但接口又与复用环境要求不一致。”的情况,在遗留代码复用,类库迁移等方面有用。
1.Adapter_Class适配器类
通过写一个类,继承现有类且实现所需要的接口,然后在该接口含有的抽象方法中,利用现有类的方法,实现预想的功能。
2.Adapter_Object适配器对象
与适配器类的区别,是关系从继承变成了组合,在编写的类中,不是继承现有类,而是定义一个该类的对象,并且在构造函数或者其他中完成该对象的初始化,然后再利用该对象的方法,来完成接口抽象方法需要的功能。
3.接口适配器模式
当不需要全部实现接口提供的方法时,可以先设计一个抽象类实现该接口,然后在该抽象类中编写其抽象方法的默认方法(一般为空?),那么该抽象类的子类可以有选择的重写抽象类中的方法。
在java.awt包中处理监听时运用了许多Adapter,MouseAdatper(MouseMotionAdapter)就是用到接口适配器模式的抽象类,可以继承它然后有选择的重写其中的方法,完成鼠标点击的事件监听。
4.装饰器模式
允许向一个现有的对象添加新的功能,同时又不改变其结构。
在JavaIO流中运用较多,如BufferedInputStream对FileInputStream的读入进行了一个缓冲优化,就是实现了装饰器模式。
实际上,就是装饰类中应该含有被装饰类的引用,然后通过构造函数读入被装饰类的引用完成构造,再对其中的一些功能做优化。
比如,FileInputStream类中的read()方法,不管是读入单个字节,还是读入一个byte数组的长度(或者给定length),一次read就是一次IO读入,这个操作就比较耗时。而在BufferedInputStream中,同样是通过FileInputStream对象来读入,只是它有一个内置的byte[]数组当缓冲区,那么一次read()后,先将一个默认长度的byte[]数据读入到缓冲区,然后再从缓冲区读入数据。那么在没有将缓冲区内容读完前,调用read()方法都不需要再进行IO的读写操作,因此效率得到了提高。
5.享元模式
享元实际上是对不可变类的对象进行的一种共享模式,以获得在内存开销上的优化。
最简单的例子就是String对象。
6.观察者模式
……