设计模式代表了最佳的实践,是众多软件开发前辈经过相当长一段时间的试验和总结出来的理念,是一套被反复使用、经过分门别类的一套问题解决方案。合理的使用设计模式能够保证代码可靠性,让代码更容易被他人理解。足以见得学习设计模式是每一个程序猿的必修课。
设计模式有两种分类方法,也就是根据模式的目的来分和根据模式作用的范围来分。
根据模式的目的来分,可以分为创建型模式、结构型- 模式和行为型模式三种。
根据模式的作用范围来分,可以分为类模式和对象模式两种。
在JAVA中,每个类都可能拥有多个实例,就像每个人最终都会有多个孩子一样,当然也许你不想生孩子,嫌奶粉钱太贵,这个时候你就可以选择孤独一生——同样的,JAVA中的类也有这种选择,这个时候就要用到单例模式啦。
所谓的单例模式……也就是一个类在jvm虚拟机中只有一个实例。要达成这个需要三个要素。
public class Singleton { //1.私有化构造 private Singleton(){} //2.静态属性指向实例 private static Singleton instance = new Singleton(); //3.public static方法,提供静态实例对象 public static Singleton getInstance(){ return instance; } }
上面的就是一个典型的单例模式啦,也许你注意到了在这个例子中一旦类加载就会创建实例,就像饿死鬼一样,因此我们叫他饿汉式单例。我们在这个的基础上做一些变化:
public class Singleton { //1.私有化构造 private Singleton(){} //2.静态属性指向实例 private static Singleton instance = null; //3.public static方法,提供静态实例对象 public static Singleton getInstance(){ if (instance == null){ return instance = new Singleton(); } return instance; } }
在这个例子中,只有在调用getinstance方法时才会创建实例,懒得动都不想动,要你催他他才不情不愿地创建,这可不就是懒汉嘛。
至于为什么要区分饿汉和懒汉……可能在某些情况下,比如资源较多时,这样加载的时间就会很长……为了避免这样的情况,就可以使用懒汉式了。
另外,如果涉及到线程安全的问题的话,在getInstance方法前加上synchronized就可以啦。
至于用途,很多地方需要有且只有一个实例的时候,就可以使用单例模式了,比如每个人的身份证号、一个班的班长时……
工厂模式是JAVA中最常用的设计模式之一,属于创建型模式,提供了一种创建对象的最佳方式。
在这个模式中,我们创建对象时不会对客户端暴露创建逻辑,而是通过一个共同的接口来指定新创建的对象,就仿佛一个庞大的工厂,嗯,一个创建对象的工厂。
通过实例来感受一下工厂模式↓
/**假如这个工厂是一个汽车厂,首先要有一个汽车接口,里面有一个run方法*/ public interface Car { void run(); } /**奔驰车类实现了汽车接口*/ class Benz implements Car { @Override public void run() { System.out.println("嘟嘟嘟,奔驰车开动啦"); } } /**宝马车类实现了汽车接口*/ public class Bmw implements Car { @Override public void run() { System.out.println("嘟嘟嘟,宝马车启动啦"); } } /**创建汽车的工厂*/ public class CarFactory { public Car getCar(String carType){ if (carType == null){ return null; } if (carType.equalsIgnoreCase("Benz")){ return new Benz(); } if (carType.equalsIgnoreCase("Bmw")){ return new Bmw(); } return null; } } /**最后测试,就能通过工厂(CarFactory)来创建汽车(对象)啦*/ public class TestFactory { public static void main(String[] args) { CarFactory carFactory = new CarFactory(); Car benz = carFactory.getCar("Benz"); Car bmw = carFactory.getCar("Bmw"); benz.run(); bmw.run(); } }
通过上面的例子大概能够感受什么叫做工厂模式了,下面来总结一下优缺点:
前面的工厂模式考虑的是单一的产品,比如汽车……比如电视,而在抽象工厂模式中,工厂却变成了一个综合形大工厂。
一样的通过实例来感受:
/**一样的汽车接口和汽车实现类*/ public interface Car {...} class Benz implements Car {...} public class Bmw implements Car {...} /**加上另一个需求:游戏机的接口和实现类*/ public interface GameBoy { void play(); } public class PS4 implements GameBoy { @Override public void play() { System.out.println("我要打PS4游戏"); } } public class XBOX implements GameBoy { @Override public void play() { System.out.println("我要打XBOX游戏!"); } }
按照工厂模式的套路,这里要开始创建工厂了,有两个需求就要创建两个工厂,然后调用的时候需要自己创建工厂对象,这样显然不符合工厂模式的理念,那么……看来我们需要一个创建工厂的工厂↓
/**和汽车、游戏机的接口一样,也需要一个工厂接口*/ public abstract class AbstractFactory { public abstract Car getCar(String carType); public abstract GameBoy getGameBoy(String gameBoyType); } package com.designpattern.factroypattern; /**和汽车工厂一样,只不过这是一个创建工厂的工厂*/ public class Factory2Factory { public static AbstractFactory getFactory(String factoryType){ if (factoryType.equalsIgnoreCase("Car")){ return new CarFactory(); } if (factoryType.equalsIgnoreCase("GameBoy")){ return new GameBoyFactory(); } return null; } } /**测试的时候先创建工厂,再创建产品*/ public class TestFactory { public static void main(String[] args) { AbstractFactory carFactory = Factory2Factory.getFactory("Car"); Car benz = carFactory.getCar("Benz"); benz.run(); AbstractFactory gameBoyFactory = Factory2Factory.getFactory("GameBoy"); GameBoy ps4 = gameBoyFactory.getGameBoy("PS4"); ps4.play(); } }
所谓的抽象工厂模式,就是对工厂模式的一种变形,只是增加了一个制造工厂的工厂。
……