创建型模式总体上比较简单,它们的作用就是为了产生实例对象,算是各种工作的第一步了,因为我们写的是面向对象的代码,所以我们第一步当然是需要创建一个对象了。
简单工厂模式最简单;工厂模式在简单工厂模式的基础上增加了选择工厂的维度,需要第一步选择合适的工厂;抽象工厂模式有产品族的概念,如果各个产品是存在兼容性问题的,就要用抽象工厂模式。单例模式就不说了,为了保证全局使用的是同一对象,一方面是安全性考虑,一方面是为了节省资源;建造者模式专门对付属性很多的那种类,为了让代码更优美;原型模式用得最少,了解和 Object 类中的 clone() 方法相关的知识即可。
1.工厂模式
它提供了一种创建对象的最佳方式
public interface Skewer {
public String create();
}
public class PorkSkewer implements Skewer {
@Override
public String create() {
return "我烤的是猪肉串...";
}
}
public class MuttonSkewer implements Skewer {
@Override
public String create() {
return "我烤得是羊肉串...";
}
}
public class SkewerFactory {
public static Skewer getSkewer(String param){
if (param.equals("mutton")){
return new MuttonSkewer();
}else if (param.equals("pork")){
return new PorkSkewer();
}else {
return null;
}
}
public static void main(String[] args) {
Skewer mutton = SkewerFactory.getSkewer("mutton");
System.out.println(mutton.create());//我烤得是羊肉串...
System.out.println("*************");
Skewer pork = SkewerFactory.getSkewer("pork");
System.out.println(pork.create());//我烤的是猪肉串...
}
}
2.抽象工厂模式
是围绕一个超级工厂创建其他工厂,当涉及到产品族的时候,就需要引入抽象工厂模式了
/** 搞烧烤 */
public interface Skewer {
public String create();
}
public class MuttonSkewer implements Skewer {
@Override
public String create() {
return "羊肉串准备起来";
}
}
public class PorkSkewer implements Skewer {
@Override
public String create() {
return "猪肉串准备起来";
}
}
/** 搞些啤酒恰 */
public interface Beer {
public String create();
}
public class QingDaoBeer implements Beer {
@Override
public String create() {
return "青岛啤酒来了";
}
}
public class HuangheBeer implements Beer {
@Override
public String create() {
return "黄河啤酒来了";
}
}
/** 创建一个工厂,通过传递啤酒或者烧烤的信息获取工厂 */
public abstract class AbstractFactory {
abstract Skewer getSkewer(String skewerName);
abstract Beer getBeer(String beerName);
}
/** 啤酒工厂 */
public class BeerFactory extends AbstractFactory{
@Override
Skewer getSkewer(String skewerName) {
return null;
}
@Override
Beer getBeer(String beerName) {
if (beerName.equals("qingdao")){
return new QingDaoBeer();
}else if (beerName.equals("huanghe")){
return new HuangheBeer();
}else {
return null;
}
}
}
/** 烧烤工厂 */
public class SkewerFactory extends AbstractFactory {
@Override
Skewer getSkewer(String skewerName) {
if (StringUtils.isEmpty(skewerName)){
return null;
}else if (skewerName.equals("mutton")){
return new MuttonSkewer();
}else if (skewerName.equals("pork")){
return new PorkSkewer();
}
return null;
}
@Override
Beer getBeer(String beerName) {
return null;
}
}
/** 老板上菜 */
public class FactoryProduct {
public static AbstractFactory getFactory(String name){
if (name.equals("skewer")){
return new SkewerFactory();
}else if (name.equals("beer")){
return new BeerFactory();
}
return null;
}
public static void main(String[] args) {
AbstractFactory skewer = FactoryProduct.getFactory("skewer");
Skewer mutton = skewer.getSkewer("mutton");
System.out.println(mutton.create());
System.out.println("*************");
AbstractFactory beer = FactoryProduct.getFactory("beer");
Beer huanghe = beer.getBeer("qingdao");
System.out.println(huanghe.create());
}
}
3.建造者模式
使用多个简单的对象一步一步构建成一个复杂的对象
优点:
使用建造者模式可以使客户端不必知道产品内部组成的细节。
具体的建造者类之间是相互独立的,这有利于系统的扩展。
具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。
缺点:
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
public class BarbecueCake {
private String name;
private double price;
@Override
public String toString() {
return "BarbecueCake{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
// 不容许客户度直接调用构造方法
private BarbecueCake(){}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public static BarbecueCakeBuilder builder(){
return new BarbecueCakeBuilder();
}
public static class BarbecueCakeBuilder{
private String name;
private double price;
private BarbecueCakeBuilder(){}
public BarbecueCakeBuilder name(String name){
this.name=name;
return this;
}
public BarbecueCakeBuilder price(double price){
this.price=price;
return this;
}
public BarbecueCake build(){
BarbecueCake bc = new BarbecueCake();
bc.setName(this.name);
bc.setPrice(this.price);
return bc;
}
}
}
//客户端调用
public class test {
public static void main(String[] args) {
BarbecueCake b = BarbecueCake.builder()
.name("烧烤饼")
.price(6)
.build();
System.out.println(b);
}
}
4.原型模式
通过拷贝这些原型创建新的对象。
public class User implements Cloneable {
private String name;
private Integer age;
public User() { }
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
protected User clone() throws CloneNotSupportedException {
return new User(this.name,this.age);
}
public static void main(String[] args) throws CloneNotSupportedException {
User user1 = new User("张三", 6);
User userClone = user1.clone();
user1.setAge(99);
System.out.println(user1==userClone);//false
System.out.println(user1);//User{name='张三', age=99}
System.out.println(userClone);//User{name='张三', age=6}
}
}5.单例模式
注意:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
5.1懒汉式
/**
* 懒汉式 -- 线程不安全
*/
public class SingletonLayze {
private static SingletonLayze singleton;
private SingletonLayze(){}
public static SingletonLayze getSingleton(){
if (singleton==null){
return new SingletonLayze();
}
return singleton;
}
}
/**
* 懒汉式 -- 线程安全
*/
public class SingletonLayze2 {
private static SingletonLayze2 singletonLayze2;
private SingletonLayze2(){}
public static synchronized SingletonLayze2 getSingletonLayze2(){
if (singletonLayze2==null){
return new SingletonLayze2();
}
return singletonLayze2;
}
}5.2饿汉式
/**
* 饿汉式
*/
public class SingletonHungry {
private static SingletonHungry singletonHungry = new SingletonHungry();
private SingletonHungry(){}
public static SingletonHungry getInstance(){
return singletonHungry;
}
}5.3双重检锁
public class Singleton {
private volatile static Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
if (singleton==null){
synchronized (Singleton.class){
if (singleton==null){
return new Singleton();
}
}
}
return singleton;
}
}5.4登记式
public class SingletonIner {
private static class SingletonHold{
private static final SingletonIner Instance=new SingletonIner();
private SingletonHold(){}
public static SingletonIner getInstance(){
return SingletonHold.Instance;
}
}
public static void main(String[] args) {
SingletonIner singletonIner = new SingletonIner();
SingletonIner singletonIner1 = new SingletonIner();
System.out.println(singletonIner==singletonIner1);
}
}5.5枚举、
public enum SingletonEnum {
INSTANCE;
public void whateverMethod(){}
}一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式。