第三章 创建型模式简介
一、单例模式
1. 意思是:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
2. 适用场景:建立目录、数据库连接等需要单线程操作的场合,用于实现对系统资源的控制。
3.分类:饿汉式:类加载的时候就进行对象实例化
懒汉式:第一次引用类时,才进行对象实例化
3.1饿汉式(线程安全)
public class Singleton {
//1. 构造方法私有化,外部就无法创建多个实例***重要
private Singleton(){}
//2. 创建类的唯一实例,用static来修饰,可以直接用类名来获取实例
private static Singleton instance = new Singleton();
//3. 提供一个获取实例的方法
public static Singleton getInstance(){
return instance;
}
}
由于构造函数是私有的,因此不能被继承。
3.2懒汉式(线程不安全)
public class Singleton {
//1.构造方法私有化
private Singleton(){}
//2.声明类的实例
private static Singleton instance;
//3.使用实例的方法
public static Singleton getInstance(){
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3.3懒汉式(线程安全)
public class Singleton2 {
//1.构造函数私有化
private Singleton2(){}
//2.声明类的实例
private static Singleton2 instance;
//3.获取一个获得实例的方法
public static synchronized Singleton2 getInstance(){
if (instance == null) {
instance = new Singleton2();
}
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
return instance;
}
}
4.饿汉式和懒汉式的区别
(1)饿汉式在类加载时就被实例化,懒汉式是在类第一被引用时实例化
(2)从资源利用效率上说,饿汉式要差一些;但从速度和反应时间角度来讲,饿汉式单例类则比懒汉式单例类稍好些
5.单例模式的优缺点
优点:
(1)减少内存的开支,特别是一个对象需要频繁的创建、销毁时
(2)由于单例模式只生成一个实例,减少了系统的性能开销,当一个对象的产生需要比较多资源时,如读取配置文件、产生其他依赖对象时,则可以通过 在启用时直接产生一个对象,然后用永久驻留内存的方式来解决
(3)单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在于内存中,避免了对同一资源文件的同时操作
(4)单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理
缺点:
(1)单例模式无法创建子类,扩展困难
(2)单例模式对测试不利
(3)单例模式与单一职责原则有冲突
6.适用场景
(1)要求生成唯一序列号的场景
(2)在整个项目中需要一个共享访问点或共享数据.例如:一个Web页面上的计数器,可以不用每次刷新都记录到数据库中,使用单例模式保持计数器的值, 并确保是线程安全的
(3)创建一个对象需要消耗的资源过多,如访问IO或数据库等资源等
(4)需要定义大量的静态常量和静态方法的环境
7.应用
Spring框架中的每个Bean默认就是单例的;Java基础类库中的java.lang.Runtime类也采用了单例模式,其getRuntime()方法返回了唯一的实例
/*Created By guolujie 2017年10月16日*/
class NumThread extends Thread{
private String threadName;
public NumThread(String name){
threadName = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
Singleton thread1 = Singleton.getInstance();
for (int i = 0; i < 5; i++) {
System.out.println(threadName + "第" + thread1.getNum() + "次访问!");
try {
this.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
public class test {
public static void main(String[] args) {
NumThread numThread1 = new NumThread("线程A");
NumThread numThread2 = new NumThread("线程B");
numThread1.start();
numThread2.start();
}
}
运行结果:
二、工厂方法模式
1.工厂方法模式又叫虚拟构造函数模式或者多态性工厂模式。工厂方法模式的用意是,定义一个创建产品对 象的工厂接口,将实际创建性工作推迟到子类中。
2.在工厂方法模式中共涉及以下四个角色:
(1)抽象工厂角色:该角色是工厂方法模式的核心,与应用系统无关,任何在创建对象的工厂类必须实现这个接口
(2)具体工厂角色:该角色实现了抽象工厂接口,含有与应用密切相关的逻辑,并且受到应用程序的调用以创建产品对象
(3)抽象产品角色:该角色负责定义产品的共性,实现对产品最抽象的定义
(4)具体产品角色:该角色实现抽象产品角色所声明的接口,工厂方法模式所创建的每一个对象都是某个具体产品角色的实例
3.抽象工厂代码实例
3-1抽象工厂Creator.java
public interface Creator {
/*
* 工厂方法
* 创建一个产品对象,其输入参数类型可以自行设置
*/
public <T extends Product> T factory(Class<T> c);
}
3-2抽象产品Produce.java
public interface Product {
//产品类的公共方法
public void method1();
public void method2();
}
3-3具体工厂类ConcreteCreator.java
public class ConcreteCreator implements Creator {
public <T extends Product> T factory(Class<T> c){
Product product = null;
try {
product = (Product) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
// TODO: handle exception
}
return (T) product;
}
}
3-4具体产品类ConcreteProduct.java
public class ConcreteProduct implements Product {
public void method1(){
//业务逻辑处理代码
}
public void method2(){
//业务逻辑处理代码
}
}
3-5应用代码FactoryMethodDemo.java
public class FactoryMethodDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Creator creator = new ConcreteCreator();
Product product = creator.factory(ConcreteProduct.class);
/*
* 继续业务处理
*/
}
}
4.工厂方法模式的优点
优点:(1)良好的封装性,代码结构清晰
(2)优秀的可扩展性
(3)屏蔽产品类
(4)工厂方法模式是典型的解耦框架
5.工厂方法模式的适用场景
(1)工厂方法模式是new一个对象的替代品,因此在所有需要生成对象的地方都可以使用,会增加代码的复杂度
(2)需要灵活的可扩展的框架时,可以考虑采用工厂方法模式
(3)工厂方法模式可以用到异构项目中
(4)工厂方法模式可以使用在测试驱动开发的框架下
6.工厂方法模式的实例
public interface FruitGardener {
public Fruit factory();
}
public interface Fruit {
public void grow();
}
public class AppleGardener implements FruitGardener {
public Fruit factory(){
return new Apple();
}
}
public class GrapeGardener implements FruitGardener {
public Fruit factory(){
return new Grape();
}
}
public class Apple implements Fruit {
private int treeAge;
public int getTreeAge() {
return treeAge;
}
public void setTreeAge(int treeAge) {
this.treeAge = treeAge;
}
public void grow(){
System.out.println("苹果正在生长...");
}
public void harvest(){
System.out.println("收获苹果");
}
public void plant(){
System.out.println("栽种苹果");
}
}
public class Grape implements Fruit {
private boolean seedless;
public boolean isSeedless() {
return seedless;
}
public void setSeedless(boolean seedless) {
this.seedless = seedless;
}
public void grow(){
System.out.println("葡萄正在生长...");
}
public void harvest(){
System.out.println("收获葡萄");
}
public void plant(){
System.out.println("栽种葡萄");
}
}
public class ClientDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
FruitGardener fruitGardener = new AppleGardener();
Apple apple = (Apple) fruitGardener.factory();
apple.plant();
apple.grow();
apple.harvest();
fruitGardener = new GrapeGardener();
Grape grape = (Grape) fruitGardener.factory();
grape.plant();
grape.grow();
grape.harvest();
}
}