设计模式代表了最佳的实践,是众多软件开发前辈经过相当长一段时间的试验和总结出来的理念,是一套被反复使用、经过分门别类的一套问题解决方案。合理的使用设计模式能够保证代码可靠性,让代码更容易被他人理解。足以见得学习设计模式是每一个程序猿的必修课。
设计模式有两种分类方法,也就是根据模式的目的来分和根据模式作用的范围来分。
根据模式的目的来分,可以分为创建型模式、结构型- 模式和行为型模式三种。
根据模式的作用范围来分,可以分为类模式和对象模式两种。
在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();
}
}
所谓的抽象工厂模式,就是对工厂模式的一种变形,只是增加了一个制造工厂的工厂。
……