Java设计模式
工厂模式
简单工厂模式
简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。
|
|
|
|
|
|
客户端创建产品对象的时候使用Product product = Factory.getProduct("A");来实现。顶层除了抽象类以外,接口也是一种使用场景。
另外,如果用户想要更换使用的产品(例如Product product = Factory.getProduct("A");中不再需要A而是B),那么创建产品的代码则需要重新修改编译。但如果将所需要的创建的产品的信息放在xml中,而用户使用Factory类的代码不再直接写死创建某个产品,而是去xml文件中读取,那么更换所需要的产品时就无需修改任何代码了。
工厂方法模式
简单工厂模式存在缺点:
1.工厂类过于庞大,包含了大量的if…else…代码,导致维护和测试难度增大;
2.系统扩展不灵活,如果增加新类型的日志记录器,必须修改工厂类中的静态工厂方法的业务逻辑,违反了“开闭原则”。
也即简单工厂模式中的工厂类承担了太多细节,而且是写死的。
在工厂方法模式中,不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构,具体工厂和具体产品之间一一对应。
工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。

客户端代码:
|
|
显然,这种设计不存在简单工程方法中工厂类中的if-else的分支和写死的情况。使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。
抽象工厂模式
暂缺。
单例模式
饿汉式单例
类加载的时候就已经创建了单例对象。
|
|
懒汉式单例
懒汉式单例在第一次调用getInstance()方法时实例化,在类加载时并不自行实例化,这种技术又称为延迟加载(Lazy Load)技术。
1.低效率版本:
|
|
由于每次调用getInstance()方法都要进行线程锁定判断,效率会降低,事实上大量的情况是单例已经存在的情况,没必要对整个方法加synchronized。于是变成了:
2.错误版本:
|
|
虽然if判断条件可以将已有实例的情况排除在外,不会的导致降低并发效率。但由于创建实例需要时间,因此可能有多个线程同时达到了point处,那么它们最终会产生多个实例。所以需要再加一层判断:
3.高效率版本:
|
|
4.最优版本
高效率版本中还是无法避免某个层面的同步导致的性能牺牲,而如果通过静态内部类实现单例则可以同时做到延迟加载又不牺牲性能,这是被称之为Initialization Demand Holder(IoDH)的技术的技术。
|
|
客户端代码Singleton s1 = Singleton.getInstance();。
这种方式中,对于还没使用单例时,虚拟机不会加载该单例类,而第一次使用它时,虚拟机保证了线程安全,实现了延迟加载又没有牺牲性能。
原型模式
在具体原型类中定义一个能根据自身的域复制创建新的对象并返回新对象引用的方法,例如该方法名为getCloneInstance()。客户端只要创建一个具体原型类的对象并调整该对象各个域的值,然后调用getCloneInstance()方法即可得到与该原型对象相同的克隆对象。
通常对克隆所产生的对象进行修改对原型对象不会造成任何影响,通过不同的方式修改可以得到一系列相似但不完全相同的对象。
原型模式分为以下几种角色:
Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。
ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。
|
|
客户类Client中的代码:
|
|
由于客户类针对抽象原型类Prototype编程,因此用户可以根据需要选择具体
原型类,系统具有较好的可扩展性,增加或更换具体原型类都很方便。
关于Java中实现原型模式
|
|
这种浅拷贝方式只是逐域复制了引用,如果域的类型是String或其他的类,那么这种方式无法产生完全独立的新对象。下面两种解决办法:
1.保证其他的类同样也实现了Cloneable接口并重写Object.clone()方法浅拷贝每个域,一直传递这种规则直到直至边界。
2.可以通过序列化(Serialization)的方式来实现。序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。其中clone()方法示例如下:
|
|
建造者模式
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。建造者模式一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
建造者模式结构:

在建造者模式结构图中包含如下几个角色:
Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
客户端代码:
|
|
适配器模式
适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。
在适配器模式中引入了一个被称为适配器(Adapter)的包装类,而它所包装的对象称为适配者(Adaptee),即被适配的类。适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。
