本篇文章针对三个问题来学习几个常见设计模式:设计模式如何实现?设计模式的应用场景?设计模式有什么优点?
1.单例模式(singleton)
如何实现?
单例模式保证一个类有且仅有一个实例,提供一个全局访问的访问点:
class LazySingleton {
private static class LazyHolder {
private static final LazySingleton INSTANCE = new LazySingleton();
}
public static final LazySingleton getInstance() {
return LazyHolder.INSTANCE;
}
}
程序中所有代码都通过getInstance方法统一调用,保证只能获取到该类的一个实例
应用场景和优点?
单例模式中对于该类只有两种状态:没有实例和有一个实例,可以想一下windows的任务管理器,无论怎么按Shift+Ctrl+Esc来启动任务管理器,只会出现一个,只可以启动或者关掉(在java程序中就是被CG回收).
1.单例模式可以节省系统资源,如果一个程序频繁的初始化,销毁一个类,始终使用一个明显比较节能(在类不保存信息,或者保存信息固定不可以改变时比较实用,因为没办法保证其他获得到该实例的线程不去修改里面的数据).
2.比较适用于控制资源,如线程池控制类一般都是单例模式,防止创建多个线程池,影响对运行状况的判断.
单例模式有懒汉和饿汉两种模式,饿汉模式就是生成一个全局静态实例,懒汉模式即延迟加载(在使用实例时才加载)如上述代码,上述代码是利用内部静态类的加载机制来实现的,如果通过条件判断是否已经加载时,要注意线程安全问题.
2.简单工厂模式(factory)
如何实现?
如图Car是一个接口,ACar和BCar实现了该接口,并实现了drive方法,而CarFactory工厂类的作用是确定调用方用哪个实现类来实现功能,CarFactory的代码如下:
public class CarFactory {
public static Car getCar(String car)throws Exception{
if("A".equals(car)){
return new ACar();
}
if("B".equals(car)){
return new BCar();
}else {
throw new Exception();
}
}
}
调用方只要通过调用工厂类的getCar方法就可以获取到自己需要的实现类:
Car car=CarFactory.getCar("A");
car.drive();
应用场景和优点?
从调用方的代码可以看出,调用方不需要关心如何实例化,这个类中有没有想用的方法,只需要关注需要获取哪个类,调用接口中那个方法即可.
即,对于调用者来说,我不需要自己构造一辆能开的A车,我直接告诉工厂,给我一台A车(所有的车都能开),然后直接开走它.
使用工厂模式可以让自己的程序获得很强的扩展性和尽量少的修改量,将创建实例和使用实例的工作分开,并且如果需要扩展接口的实现类,只需要增加实现类和修改工厂类.
适用于具体产品数量较少的情况,如果产品数量较多需要使用抽象工厂模式.
3.抽象工厂(Abstract Factory)
如何实现?
上边的例子中,如果这时出现了car之外的另一个产品:行车记录仪tachograph,同样有tachographA和tachographB,而car和tachograph通常情况下要同时使用或者关联较强,这时变用到了抽象工厂:
public abstract class Factory{
public abstract Car creator();
public abstract Tachograph creator();
}
public class AFactory extends Factory{
public Car creator(){
return new ACar();
}
public Tachograph creator(){
return new TachographA();
}
}
public class BFactory extends Factory{
public Sample creator(){
return new BCar();
}
public Sample2 creator(String name){
return new TachographB();
}
}
这时就根据产品型号不同分成了两个工厂,A工厂(A型号的Car和A型号的tachograph可以在一起使用)和B工厂(同理),这时,调用方就可以根据自己需求,想用哪一种型号的产品组合,而确定需要从哪个工厂获取产品
应用场景和优点?
这种抽象工厂包含上述简单工厂的所有优点,可以解决情况复杂,产品多样化的需求实现,当然代价就是实现较为复杂,各个工厂的介绍容易使人混淆,可以根据自己的需求而确定自己的工厂模式实现方式.
工厂模式使用于提供的某实例或某些相关联的实例种类较多的情况,或者是该实例创建方式灵活扩展的可能性较大的情况.将创建实例和使用实例的工作分开,如JUC中线程池创建新线程的方式是多样话的并且是可扩展的,就是用ThreadFactory可扩展接口来实现
4.构造者设计模式(Builder)
如何实现?
构造者模式主要是实现不同的构造者builder,然后通过一个领导director将构造者构造出来的成果物整合在一起生产出实例.
可以看下简单的实现类构成,BuilderPerson是一个抽象类:
abstract class BuilderPerson{
public Person Person;
public Person getPerson() {
return Person;
}
public BuilderPerson(){
Person=new Person();
}
abstract void setName();
abstract void setAge();
abstract void setSex();
}
colleage为构建大学生类,pupil为构建小学生类:
public class Colleage extends BuilderPerson{
void setName() {
this.Person.setName("大学生");
}
void setAge() {
this.Person.setAge(21);
}
void setSex() {
this.Person.setSex("女");
}
}
public class Pupil extends BuilderPerson{
void setName() {
this.Person.setName("小学生");
}
void setAge() {
this.Person.setAge(7);
}
void setSex() {
this.Person.setSex("男");
}
}
personDriector类为领导综合类:
public class PersonDirector{
private BuilderPerson builderPerson;
public void setBuilderPerson(BuilderPerson builderPerson) {
this.builderPerson = builderPerson;
}
public BuilderPerson getBuilderPerson() {
return builderPerson;
}
public void createPerson(){
builderPerson.setAge();
builderPerson.setName();
builderPerson.setSex();
}
}
测试用构造者模式生成一个小学生:
PersonDirector personDirector=new PersonDirector();
BuilderPerson pupil=new Pupil();
personDirector.setBuilderPerson(pupil);
personDirector.createPerson();
System.out.println(personDirector.getBuilderPerson().getPerson());
应用场景和优点?
该设计模式可以根据不同的构造器来构造实例,可扩展性强,通过继承抽象类的方式形成的构造器系统也可以明了的看出构造器构造的大致顺序,代码阅读性较强.
适用于构建复杂的对象实例,或者构建过程复杂多样的对象实例,和工厂模式的区别是构建者模式更偏向于不同的构建过程,而工厂模式更注重对象的不同种类.