设计模式学习(二)——创建型模式(单例、工厂、建造者)

单例模式

单例模式:保证一个类仅有一个实例,并且这个类提供一个全局的访问接口,某些对象在全局只需要一个,就可以使用单例模式。

单例模式的创建可以分为两种模式:提前加载和延迟加载。

提前加载模式:

    public class Singleton {
        
        private static Singleton instance = new Singleton();
        private Singleton(){}
        
        public static Singleton getInstance(){
            return instance;
        }
    }

也叫饿汉式,它通过静态变量实现了全局只保证存在一个实例,保证了线程安全。但是,这种方式有一个明显的缺点,如果在程序某一次执行时一直没有用到这个实例,那就造成了资源的浪费,同时,使用全局变量也使程序变得难以调试与维护。

枚举方式:

public enum Singleton {
	 //定义一个枚举的元素,它就是 Singleton 的一个实例
    INSTANCE;  
    
    public void doSomething(){}
}

//使用方法
public class Test {

	public static void main(String[] args) {
		Singleton singleton = Singleton.INSTANCE;
		singleton.doSomething();

	}
}

延迟加载:

public class Singleton {  

      private static Singleton instance;  
      private Singleton (){ }   

      public static Singleton getInstance() {
          //判断当前单例是否已经存在,若存在则返回,不存在则再建立单例
	      if (instance == null) {  
              // 1
	          instance = new Singleton();  
	      }  
	      return instance;  
      }  
 }

上面创建单例是存在问题的,当一个线程走到 1 是,尚未来得及创建出对象,另一个线程也走到 1,就会打破单例,创建出多个对象。要解决线程安全问题,我们可以给 getInstance() 这个方法加一个 synchronized 关键字,或者 使用 synchronized() 修饰这段代码块,具体如下:

// 1.
public class Singleton {  

      private static Singleton instance;  
      private Singleton (){ }   

      public static synchronized Singleton getInstance() {
      
	      if (instance == null) {  
	          instance = new Singleton();  
	      }  
	      return instance;  
      }  
 }
// 2.
public class Singleton {  

      private static Singleton instance;  
      private Singleton (){ }   

      public static Singleton getInstance() {
      
      	synchronized(this) {
      		if (instance == null) {  
	          	instance = new Singleton();  
	      	}  
      	} 
      	return instance;
      }  
 }

这样,我们就解决了线程安全的问题。但这样又会出现一个问题,每次调用 getInstance() 都会经过加锁这一层,会带来很多不必要的时间消耗,所以,我们在锁外在进行一次判断就会大大节省开支:

public class Singleton {  

      private volatile static Singleton instance;  
      private Singleton (){ }   

      public static Singleton getInstance() {
      	if (instance == null) {
      		synchronized(this) {
      			if (instance == null) {  
	          		instance = new Singleton();  
	      		}  
      		} 
      	}
      	return instance;
      }  
 }

这里,我们还加了 volatile 关键字来保证 对象在创建时,多线程对其的正确处理。这样,已经完全可以确保线程安全了。

工厂模式

简单工厂模式:

也叫静态工厂模式,客户传入不同的参数,就可以得到不同的对象。

// 产品接口:手机是产品,里面有个方法可以展示操作系统
public interface Phone {
    
    void showSystem();
    
}

// 具体产品 Android or iOS
public class AndroidPhone implements Phone{
    @Override
    public void showSystem() {
        System.out.println("我是Android系统");
    }
}

public class iOSPhone implements Phone{
    @Override
    public void showSystem() {
        System.out.println("我是iOS系统");
    }
}

// 工厂负责按需造手机
public class PhoneFactory {

    public static Phone create(String phone){

        Phone mPhone;

        switch (phone){

            case "Android":
                mPhone = new AndroidPhone();
                break;
            case "iOS":
                mPhone = new iOSPhone();
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + phone);
        }
        return mPhone;
    }

}

// 客户就可以得到想要的手机了
public class Customer {

    @Test
    public void test(){

        // 来个Android的
        Phone Android = PhoneFactory.create("Android");
        Android.showSystem();

    }
}

工厂方法模式:

是简单工厂模式的进一步深化,我们不再提供统一的工厂去创建对象,在工厂方法模式中,工厂类被抽象化,继而由它的子类去实现对象的实例化。这样我们在扩展工厂时就不会破坏开闭原则。

//工厂接口
public interface PhoneFactory {

      Phone create();

}

//工厂具体
public class AndroidFactory implements PhoneFactory{
    @Override
    public Phone create() {
        return new AndroidPhone();
    }
}

public class iOSFactory implements PhoneFactory{
    @Override
    public Phone create() {
        return new iOSPhone();
    }
}

//客户
public class Customer {

    @Test
    public void test(){

        // 来一个Android的
        AndroidFactory androidFactory = new AndroidFactory();
        Phone android = androidFactory.create();
        android.showSystem();
    }
}

随着国产手机操作系统的崛起,我们是时候扩展扩展我们的工厂了:

//新增手机
public class HarmonyPhone implements Phone{

    @Override
    public void showSystem() {
        System.out.println("我是鸿蒙的");
    }
}

//新增工厂
public class HarmonyOSFactory implements PhoneFactory{
    @Override
    public Phone create() {
        return new HarmonyPhone();
    }
}

//客户
public class Customer {

    @Test
    public void test(){

        // 来一个Android的
        AndroidFactory androidFactory = new AndroidFactory();
        Phone android = androidFactory.create();
        android.showSystem();

        // 来个鸿蒙的
        HarmonyOSFactory harmonyOSFactory = new HarmonyOSFactory();
        Phone harmony = harmonyOSFactory.create();
        harmony.showSystem();
    }
}

这就是工厂方法模式。但是随着我们产品的增多,代码量巨增。

抽象工厂模式:

抽象工厂模式又是工厂方法模式的扩展版,它不再创建一个单一的对象,而是创建一系列相关的对象。

继续拿上面的例子来说,手机除了操作系统,还分国产和进口。

//国产Android手机
public class ChinaAndroid implements AndroidPhone{
    @Override
    public void showSystem() {
        System.out.println("国产Android");
    }
}

//国产iOS手机
public class ChinaIOS implements iOSPhone{
    @Override
    public void showSystem() {
        System.out.println("国产iOS");
    }
}

//进口Android手机
public class ImportAndroid implements AndroidPhone{
    @Override
    public void showSystem() {
        System.out.println("进口Android");
    }
}

//进口iOS手机
public class ImportIOS implements iOSPhone{
    @Override
    public void showSystem() {
        System.out.println("进口iOS");
    }
}

//国产工厂
public class ChinaFactory implements PhoneFactory{
    @Override
    public AndroidPhone createAndroid() {
        return new ChinaAndroid();
    }

    @Override
    public iOSPhone createiOS() {
        return new ChinaIOS();
    }
}

//进口工厂
public class ImportFactory implements PhoneFactory{
    @Override
    public AndroidPhone createAndroid() {
        return new ImportAndroid();
    }

    @Override
    public iOSPhone createiOS() {
        return new ImportIOS();
    }
}

//客户
public class Customer {

    @Test
    public void test(){
        // 国产工厂
        PhoneFactory chinaFactory = new ChinaFactory();
        AndroidPhone androidPhone = chinaFactory.createAndroid();
        iOSPhone iOSPhone = chinaFactory.createiOS();
        androidPhone.showSystem();
        iOSPhone.showSystem();

    }
}

OK,这就是抽象工厂模式。

介绍到这里,我们发现三种不同的方式存在着很多重叠的地方,而且,设计模式并不存在着明确的定义,关键在于要了解其中的核心思想。工厂模式的核心概念就是利用工厂来创建对象,而不应该将对象的创建交给一个和此对象无关的类,就上面例子而言,难道客户还要负责去自己造出一个手机吗?

建造者模式

正常的建造者模式

建造者模式允许用户在不知道内部构造的情况下,一步步精细控制对象的构造流程来创造出一个复杂对象。当我们构建不同的对象时,可以通过构造不同的建造者来进行实例化。

建造者包含以下类:

  • Product(产品类):这是需要为它构建的类。
  • Builder(抽象建造者类):用于声明需要构建产品的组成部分。
  • ConcreteBuilder(具体建造者):实现抽象建造者中声明的方法。
  • Director(指挥者):指导如何构建对象的类。

举个例子,构建一个程序员?

//产品类
public class Programmer {

    private int age;

    private String language;

    private int salary;

    public void setAge(int age) {
        this.age = age;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public int getAge() {
        return age;
    }

    public int getSalary() {
        return salary;
    }

    public String getLanguage() {
        return language;
    }
}

//抽象构建者
abstract class Builder {

    abstract void buildAge();

    abstract void buildSalary();

    abstract void buildlanguage();

}

//具体构建者
public class ConcreteBuilder extends Builder{

    Programmer programmer = new Programmer();

    @Override
    void buildAge() {
       programmer.setAge(25);
    }

    @Override
    void buildSalary() {
        programmer.setSalary(20000);
    }

    @Override
    void buildlanguage() {
        programmer.setLanguage("Java");
    }
}

//指导类
public class Director {

    public void construct(Builder builder){
        builder.buildAge();
        builder.buildSalary();
        builder.buildlanguage();
    }

}

//Boss
public class Boss {

    @Test
    public void test(){
        Director director = new Director();
        ConcreteBuilder concreteBuilder = new ConcreteBuilder();
        director.construct(concreteBuilder);
        Programmer programmer = concreteBuilder.programmer;
        System.out.println("age: " + programmer.getAge() + "\n" +
                            "salary: " + programmer.getSalary() + "\n" +
                            "language: " + programmer.getLanguage());

    }

}

拥有方法链的匿名建造者:

我们再举一个例子

public class Computer {
    protected String mBoard;
    protected String mDisplay;
    protected String mCpu;
    protected String mGpu;
    protected String mOs;

    public void setBoard(String board) {
        mBoard = board;
    }

    public void setDisplay(String display) {
        mDisplay = display;
    }

    public void setCpu(String cpu) {
        mCpu = cpu;
    }

    public void setGpu(String gpu) {
        mGpu = gpu;
    }

    public void setOs(String os) {
        mOs = os;
    }

    public static class Builder {
        Computer computer;

        public Builder() {
            computer = new Computer();
        }

        public Builder board(String board) {
            computer.setBoard(board);
            return this;
        }

        public Builder display(String display) {
            computer.setDisplay(display);
            return this;
        }

        public Builder cpu(String cpu) {
            computer.setCpu(cpu);
            return this;
        }

        public Builder gpu(String gpu) {
            computer.setGpu(gpu);
            return this;
        }

        public Builder os(String os) {
            computer.setOs(os);
            return this;
        }

        public Computer build() {
            return computer;
        }
    }
}

//使用方法
public void compyter(){

    Computer computer = new Computer.Builder()
                        .board("")
                        .display("")
                        .cpu("")
                        .gpu("")
                        .os("")
                        .build();
    }

工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。

创建型模式还有原型模式对象池模式,有时间我们再继续探究。

参考:《Java设计模式及实践》

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值