设计模式系列 - 创建型模式
单例模式
懒汉式,线程不安全。
除非是单线程程序,否则不推荐使用。
public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
饿汉式,线程安全
当程序总是使用这个类的实例时,或者在资源和时间方面创建实例的成本不太大时,可以使用它。
可能导致资源浪费。因为类的实例总是被创建的,不管它是否必需。在创建实例时也会浪费CPU时间。
无法处理异常。
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }
静态块,线程安全
对象是在静态块中创建的,这样我们就可以访问它的创建,比如异常处理。同样地,对象也是在类加载时创建的。
当在创建具有紧急初始化的对象时可能出现异常时,可以使用它。可能导致资源浪费。因为类的实例总是被创建的,不管它是否必需。
public class Singleton { // public instance public static Singleton instance; private Singleton() { // private constructor } { // static block to initialize instance instance = new Singleton(); } }
同步方式,线程安全
会导致性能下降
public class Singleton { // private instance, so that it can be // accessed by only by getInstance() method private static Singleton instance; private Singleton() { // private constructor } //synchronized method to control simultaneous access synchronized public static Singleton getInstance() { if (instance == null) { // if instance is null, initialize instance = new Singleton(); } return instance; } }
双检方式,线程安全
克服了同步代码的开销问题。延迟初始化,可以用于高性能的多线程应用。
public class Singleton { // private instance, so that it can be // accessed by only by getInstance() method private static Singleton instance; private Singleton() { // private constructor } public static Singleton getInstance() { if (instance == null) { //synchronized block to remove overhead synchronized (Singleton.class) { if(instance==null) { // if instance is null, initialize instance = new Singleton(); } } } return instance; } }
内部静态类方案,优方案
加载单例类时,不会加载内部类,因此在加载类时不会创建对象。只有在调用getInstance()方法时才创建内部类。它是懒惰的初始化。
这是最广泛使用的方法,因为它不使用同步,性能更好。
public class Singleton { private Singleton() { // private constructor } // Inner class to provide instance of class private static class BillPughSingleton { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return BillPughSingleton.INSTANCE; } }
枚举,优方案
自动支持序列化机制,绝对防止多次实例化。这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
public enum Singleton { INSTANCE; public void whateverMethod() { } }
工厂方法
是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
//定义车类 public enum CarType { SMALL, SEDAN, LUXURY } //车的基类 public abstract class Car { public Car(CarType model) { this.model = model; arrangeParts(); } private void arrangeParts() { // Do one time processing here } // Do subclass level processing in this method protected abstract void construct(); private CarType model = null; public CarType getModel() { return model; } public void setModel(CarType model) { this.model = model; } } //豪华车 public class LuxuryCar extends Car { LuxuryCar() { super(CarType.LUXURY); construct(); } @Override protected void construct() { System.out.println("Building luxury car"); // add accessories } } public class SmallCar extends Car { SmallCar() { super(CarType.SMALL); construct(); } @Override protected void construct() { System.out.println("Building small car"); // add accessories } } public class SedanCar extends Car { SedanCar() { super(CarType.SEDAN); construct(); } @Override protected void construct() { System.out.println("Building sedan car"); // add accessories } } public class CarFactory { public static Car buildCar(CarType model) { Car car = null; switch (model) { case SMALL: car = new SmallCar(); break; case SEDAN: car = new SedanCar(); break; case LUXURY: car = new LuxuryCar(); break; default: // throw some exception break; } return car; } } public class TestFactoryPattern { public static void main(String[] args) { System.out.println(CarFactory.buildCar(CarType.SMALL)); System.out.println(CarFactory.buildCar(CarType.SEDAN)); System.out.println(CarFactory.buildCar(CarType.LUXURY)); } }
抽象工厂
围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
我们重用上一节的CarType
public abstract class Car { public Car(CarType model, Location location){ this.model = model; this.location = location; } protected abstract void construct(); private CarType model = null; private Location location = null; //getters and setters @Override public String toString() { return "Model- "+model + " built in "+location; } } public enum Location { DEFAULT, USA, ASIA } public class LuxuryCar extends Car { public LuxuryCar(Location location) { super(CarType.LUXURY, location); construct(); } @Override protected void construct() { System.out.println("Building luxury car"); //add accessories } } public class AsiaCarFactory { public static Car buildCar(CarType model) { Car car = null; switch (model) { case SMALL: car = new SmallCar(Location.ASIA); break; case SEDAN: car = new SedanCar(Location.ASIA); break; case LUXURY: car = new LuxuryCar(Location.ASIA); break; default: //throw some exception break; } return car; } } public class DefaultCarFactory { public static Car buildCar(CarType model) { Car car = null; switch (model) { case SMALL: car = new SmallCar(Location.DEFAULT); break; case SEDAN: car = new SedanCar(Location.DEFAULT); break; case LUXURY: car = new LuxuryCar(Location.DEFAULT); break; default: //throw some exception break; } return car; } } public class USACarFactory { public static Car buildCar(CarType model) { Car car = null; switch (model) { case SMALL: car = new SmallCar(Location.USA); break; case SEDAN: car = new SedanCar(Location.USA); break; case LUXURY: car = new LuxuryCar(Location.USA); break; default: //throw some exception break; } return car; } } public class CarFactory { private CarFactory() { //Prevent instantiation } public static Car buildCar(CarType type,Location location) { Car car = null; //Use location specific car factory switch(location) { case USA: car = USACarFactory.buildCar(type); break; case ASIA: car = AsiaCarFactory.buildCar(type); break; default: car = DefaultCarFactory.buildCar(type); } return car; } } public class TestFactoryPattern { public static void main(String[] args) { System.out.println(CarFactory.buildCar(CarType.SMALL,Location.USA)); System.out.println(CarFactory.buildCar(CarType.SEDAN,Location.USA)); System.out.println(CarFactory.buildCar(CarType.LUXURY,Location.ASIA)); } }
这两个工厂模式的代码还有很多switch,仅仅是演示而已
建造者模式
建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。
interface HousePlan { public void setBasement(String basement); public void setStructure(String structure); public void setRoof(String roof); public void setInterior(String interior); } class House implements HousePlan { private String basement; private String structure; private String roof; private String interior; public void setBasement(String basement) { this.basement = basement; } public void setStructure(String structure) { this.structure = structure; } public void setRoof(String roof) { this.roof = roof; } public void setInterior(String interior) { this.interior = interior; } } interface HouseBuilder { public void buildBasement(); public void buildStructure(); public void bulidRoof(); public void buildInterior(); public House getHouse(); } class IglooHouseBuilder implements HouseBuilder { private House house; public IglooHouseBuilder() { this.house = new House(); } public void buildBasement() { house.setBasement("Ice Bars"); } public void buildStructure() { house.setStructure("Ice Blocks"); } public void buildInterior() { house.setInterior("Ice Carvings"); } public void bulidRoof() { house.setRoof("Ice Dome"); } public House getHouse() { return this.house; } } class TipiHouseBuilder implements HouseBuilder { private House house; public TipiHouseBuilder() { this.house = new House(); } public void buildBasement() { house.setBasement("Wooden Poles"); } public void buildStructure() { house.setStructure("Wood and Ice"); } public void buildInterior() { house.setInterior("Fire Wood"); } public void bulidRoof() { house.setRoof("Wood, caribou and seal skins"); } public House getHouse() { return this.house; } } class CivilEngineer { private HouseBuilder houseBuilder; public CivilEngineer(HouseBuilder houseBuilder) { this.houseBuilder = houseBuilder; } public House getHouse() { return this.houseBuilder.getHouse(); } public void constructHouse() { this.houseBuilder.buildBasement(); this.houseBuilder.buildStructure(); this.houseBuilder.bulidRoof(); this.houseBuilder.buildInterior(); } } class Builder { public static void main(String[] args) { HouseBuilder iglooBuilder = new IglooHouseBuilder(); CivilEngineer engineer = new CivilEngineer(iglooBuilder); engineer.constructHouse(); House house = engineer.getHouse(); System.out.println("Builder constructed: "+ house); } }
以上是做分部建造,还可以避免new product的过多参数,比如:
public User (String firstName, String lastName, int age, String phone){ ... } public User (String firstName, String lastName, String phone, String address){ ... } public User (String firstName, String lastName, int age){ ... } public User (String firstName, String lastName){ ... }
如果再多十几个属性怎么办?
public class User { //All final attributes private final String firstName; // required private final String lastName; // required private final int age; // optional private final String phone; // optional private final String address; // optional private User(UserBuilder builder) { this.firstName = builder.firstName; this.lastName = builder.lastName; this.age = builder.age; this.phone = builder.phone; this.address = builder.address; } //All getter, and NO setter to provde immutability public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } public String getPhone() { return phone; } public String getAddress() { return address; } @Override public String toString() { return "User: "+this.firstName+", "+this.lastName+", "+this.age+", "+this.phone+", "+this.address; } public static class UserBuilder { private final String firstName; private final String lastName; private int age; private String phone; private String address; public UserBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public UserBuilder age(int age) { this.age = age; return this; } public UserBuilder phone(String phone) { this.phone = phone; return this; } public UserBuilder address(String address) { this.address = address; return this; } //Return the finally consrcuted User object public User build() { User user = new User(this); validateUserObject(user); return user; } private void validateUserObject(User user) { //Do some basic validations to check //if user object does not break any assumption of system } } } public static void main(String[] args) { User user1 = new User.UserBuilder("Lokesh", "Gupta") .age(30) .phone("1234567") .address("Fake address 1234") .build(); System.out.println(user1); User user2 = new User.UserBuilder("Jack", "Reacher") .age(40) .phone("5655") //no address .build(); System.out.println(user2); User user3 = new User.UserBuilder("Super", "Man") //No age //No phone //no address .build(); System.out.println(user3); }
原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。原型设计模式用于应用程序需要创建一个类的多个实例的场景中,这些实例几乎具有相同的状态或差别非常小。
在这个设计模式中,实际对象的一个实例(即prototype)是在启动时创建的,然后每当需要新实例时,就克隆这个原型以拥有另一个实例。这种模式的主要优点是具有最小的实例创建过程
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
public interface PrototypeCapable extends Cloneable { public PrototypeCapable clone() throws CloneNotSupportedException; } public class Movie implements PrototypeCapable { private String name = null; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Movie clone() throws CloneNotSupportedException { System.out.println("Cloning Movie object.."); return (Movie) super.clone(); } @Override public String toString() { return "Movie"; } } public class Album implements PrototypeCapable { private String name = null; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Album clone() throws CloneNotSupportedException { System.out.println("Cloning Album object.."); return (Album) super.clone(); } @Override public String toString() { return "Album"; } } public class Show implements PrototypeCapable { private String name = null; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Show clone() throws CloneNotSupportedException { System.out.println("Cloning Show object.."); return (Show) super.clone(); } @Override public String toString() { return "Show"; } } public class PrototypeCache { public static class ModelType { public static final String MOVIE = "movie"; public static final String ALBUM = "album"; public static final String SHOW = "show"; } private static java.util.Map<String , PrototypeCapable> prototypes = new java.util.HashMap<String , PrototypeCapable>(); static { prototypes.put(ModelType.MOVIE, new Movie()); prototypes.put(ModelType.ALBUM, new Album()); prototypes.put(ModelType.SHOW, new Show()); } public static PrototypeCapable getInstance(final String s) throws CloneNotSupportedException { return ((PrototypeCapable) prototypes.get(s)).clone(); } } TestPrototypePattern public class TestPrototypePattern { public static void main(String[] args) { try { String moviePrototype = PrototypeCache.getInstance(ModelType.MOVIE).toString(); System.out.println(moviePrototype); String albumPrototype = PrototypeCache.getInstance(ModelType.ALBUM).toString(); System.out.println(albumPrototype); String showPrototype = PrototypeCache.getInstance(ModelType.SHOW).toString(); System.out.println(showPrototype); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
Singleton