设计模式之创建型模式
创建型模式主要是用于创建对象,主要分为5大类:工厂方法模式(factory method pattern)、抽象工厂模式(Abstract factory pattern)、单例模式(Singleton pattern)、建造者模式(Builder pattern)、原型模式(prototype pattern)。
一、工厂方法模式(factory method pattern)
工厂方法模式主要分为三种:普通工厂模式、多工厂方法模式、静态工厂方法模式
1、普通工厂模式:创建一个工厂类,为有共同接口的类创建对象;通过传入的值和工厂类的判断条件进行匹配,创建不同的对象。
//对象的共同接口 public interface Phone { void call(); } public class MiPhone implements Phone{ @Override public void call() { System.out.println("雷布斯为你打call,,,,"); } } public class IPhone implements Phone { @Override public void call() { System.out.println("果粉为你打call。。。。。。。。"); } } public class HuaWeiPhone implements Phone { @Override public void call() { System.out.println("华为海军为你打call!!!!"); } } //对象的生产工厂 public class PhoneFactory { public Phone produce(String type){ if("小米".equals(type)){ return new MiPhone(); }else if("华为".equals(type)){ return new HuaWeiPhone(); }else if("苹果".equals(type)){ return new IPhone(); }else { return null; } } } //测试类 public class FactoryMethodPatternTest { public static void main(String[] args) { PhoneFactory phoneFactory = new PhoneFactory(); Phone xiaomi = phoneFactory.produce("小米"); Phone huawei = phoneFactory.produce("华为"); Phone pingguo = phoneFactory.produce("苹果"); xiaomi.call(); huawei.call(); pingguo.call(); } }
2、多工厂方法模式:对普通工厂方法模式进行改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,直接调用不同的方法来创建不同的对象,这样不容易出错。
/** *只需要将工厂方法和调用方法修改一下 */ //多方法对象的生产工厂 public class PhoneFactory { public Phone produceMiPhone(){ return new MiPhone(); } public Phone produceHuaweiPhone(){ return new HuaWeiPhone(); } public Phone produceIPhone(){ return new IPhone(); } } //测试类 public class FactoryMethodPatternTest { public static void main(String[] args) { PhoneFactory phoneFactory = new PhoneFactory(); Phone xiaomi = phoneFactory.produceMiPhone(); Phone huawei = phoneFactory.produceHuaweiPhone(); Phone pingguo = phoneFactory.produceIPhone(); xiaomi.call(); huawei.call(); pingguo.call(); } }
3、静态工厂方法模式:将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
//静态方法对象的生产工厂 public class PhoneFactory { public static Phone produceMiPhone(){ return new MiPhone(); } public static Phone produceHuaweiPhone(){ return new HuaWeiPhone(); } public static Phone produceIPhone(){ return new IPhone(); } } //测试类 public class FactoryMethodPatternTest { public static void main(String[] args) { Phone xiaomi = PhoneFactory.produceMiPhone(); Phone huawei = PhoneFactory.produceHuaweiPhone(); Phone pingguo = PhoneFactory.produceIPhone(); xiaomi.call(); huawei.call(); pingguo.call(); } }
二、抽象工厂模式(Abstract factory pattern)
上面的工厂方法模式如果要扩展就必须修改代码,这样就违反了开闭原则。抽象工厂模式将对象的生产工厂也进行抽象,方便程序扩展。
//对象生产工厂接口 public interface PhoneFactory { Phone produce(); } public class MiPhoneFactory implements PhoneFactory{ @Override public Phone produce() { return new MiPhone(); } } public class HuaWeiPhoneFactory implements PhoneFactory{ @Override public Phone produce() { return new HuaWeiPhone(); } } public class IPhoneFactory implements PhoneFactory { @Override public Phone produce() { return new IPhone(); } } //测试类 public class AbstractFactoryPatternTest { public static void main(String[] args) { PhoneFactory miPhoneFactory = new MiPhoneFactory(); PhoneFactory huaWeiFactory = new HuaWeiPhoneFactory(); PhoneFactory iphoneFactory = new IPhoneFactory(); Phone miPhone = miPhoneFactory.produce(); Phone huaWeiPhone = huaWeiFactory.produce(); Phone iPhone = iphoneFactory.produce(); miPhone.call(); huaWeiPhone.call(); iPhone.call(); } }
三、单例模式(Singleton pattern):
单例模式主要分为:饿汉式、懒汉式、双重检测锁、静态内部类、枚举类
1、饿汉式:顾名思义就是很饥饿,还不需要该对象的时候就直接创建该对象。
//饿汉单例模式 public class Singleton { //在类的初始化阶段就直接创建好对象 private static Singleton instance = new Singleton(); //私有化构造方法,保证无法创建更多对象,该对象只能通过getInstance方法来进行获取 private Singleton(){} public static Singleton getInstance(){ return instance; } }
2、懒汉式:需要用到该对象的时候才会区创建对象
//懒汉单例模式,只在第一次需要的时候才会创建对象,有线程安全问题 public class Singleton2 { private static Singleton2 instance = null; private Singleton2 (){} public static Singleton2 getInstance(){ if( instance == null ){ instance = new Singleton2(); } return instance; } }
//懒汉单例模式,只在第一次需要的时候才会创建对象,没有线程安全问题,但是每次取对象的时候都需要获取锁,影响效率 public class Singleton3 { private static Singleton3 instance = null; private Singleton3 (){} public static synchronized Singleton3 getInstance(){ if( instance == null ){ instance = new Singleton3(); } return instance; } }
3、双重检测锁模式:在懒汉式基础上改进,效率比懒汉式要高。
//双重检测锁单例模式,是线程安全的,并且只有前几次需要获取锁,效率比饿汉线程安全模式高。 //但是由于jvm底层的原因,在创建对象的时候有可能出现指令重排,后面的线程获取了还未初始化的对象,并且去执行对应的方法,这样就会出现问题。 //可以通过volatile 来防止指令重排 public class Singleton4 { private static Singleton4 instance = null; private Singleton4 (){} public static Singleton4 getInstance(){ if( instance == null ){ synchronized (Singleton4.class) { if( instance == null ){ instance = new Singleton4(); } } } return instance; } }
3.1、补充
//这种方式貌似能够解决双重检测锁的问题 public class Singleton7 { private static Singleton7 instance = null; private Singleton7 (){} private static synchronized void createSingleton7(){ instance = new Singleton7(); } public static Singleton7 getInstance(){ if( instance == null ){ synchronized (Singleton7.class) { if( instance == null ){ createSingleton7(); } } } return instance; } }
4、静态内部类模式:运用静态内部类的特性来构造单例
//静态内部类单例模式,这种方式线程安全并且是懒加载 public class Singleton5 { private Singleton5 (){} public static class SingletonContainer{ private static Singleton5 instance = new Singleton5(); } public static Singleton5 getInstance(){ return SingletonContainer.instance; } }
5、枚举类:枚举类的元素本身就是单例对象。
//枚举类的元素就是单例的,并且无线程安全问题。在序列化和反序列化之后也能保证单例 public enum Singleton6 { INSTANCE; //需要执行的操作 public void doSomeThing(){} }
四、建造者模式(Builder pattern)
建造者模式又名创建者模式,是将一个复杂对象的构建过程与它的表示分离,从而使得相同的构建过程可以创建不同的表示;创建者模式隐藏了复杂对象的创建过程,它把复杂对象的构建加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。
与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
public class Car { private String Body; private String wheel; public String getBody() { return Body; } public void setBody(String body) { Body = body; } public String getWheel() { return wheel; } public void setWheel(String wheel) { this.wheel = wheel; } @Override public String toString() { return "Car [Body=" + Body + ", wheel=" + wheel + "]"; } }
public interface Builder { void buildBody(); void buildWheel(); Car getCar(); } public class BenzBuilder implements Builder { private String body; private String wheel; @Override public void buildBody() { this.body = "奔驰车身"; } @Override public void buildWheel() { this.wheel = "奔驰轮子"; } @Override public Car getCar() { Car car = new Car(); car.setBody(body); car.setWheel(wheel); return car; } }
//对车辆进行组装 public class Director { private Builder builder; public Director(Builder builder){ this.builder = builder; } public void setBuilder(Builder builder){ this.builder = builder; } //组装车辆 public Car constructCar(){ builder.buildBody(); builder.buildWheel(); builder.buildWheel(); builder.buildWheel(); builder.buildWheel(); return builder.getCar(); } } //测试 public class BuilderTest { public static void main(String[] args) { Builder benzBuilder = new BenzBuilder(); Director director2= new Director(benzBuilder); Car car2 = director2.constructCar(); System.out.println(car2); } }
五、原型模式(prototype pattern)
原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。直接创建对象的代价比较大时,则采用这种模式。
浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了。
java中通过clone来实现对象的浅复制,一个原型类,只需要实现Cloneable接口,覆写clone方法就可以实现浅复制。通过实现Serializable 接口然后通过序列化和反序列化进行深度复制。
public class Prototype implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String name; private List<String> list; public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } protected Object deepClone() throws IOException, ClassNotFoundException { /* 写入当前对象的二进制流 */ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); /* 读出二进制流产生的新对象 */ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } @Override public String toString() { return "Prototype [name=" + name + ", list=" + list + "]"; } }
public class PrototypeTest { public static void main(String[] args) throws Exception { Prototype p = new Prototype(); p.setName("a"); List<String> list = new ArrayList<>(); list.add("b"); p.setList(list); System.out.println(p); //浅复制 Prototype p1 = (Prototype)p.clone(); System.out.println(p1); //深复制 Prototype p2 = (Prototype)p.deepClone(); System.out.println(p2); System.out.println("------------------------------"); //修改原型的值,发现复制后的对象的值也被修改了 list.add("c"); p.setName("A"); p.setList(list); System.out.println(p); System.out.println(p1); System.out.println(p2); } }