设计模式系列 - 创建型模式

单例模式

设计模式系列 - 创建型模式

懒汉式,线程不安全。

除非是单线程程序,否则不推荐使用。

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