单例模式与工厂模式
参考教程:https://www.bilibili.com/video/BV1G4411c7N4
代码实现 Github:https://github.com/yaokuku123/pattern
概述
设计模式分为三大类型,共23种
- 创建者模式:单例模式,工厂模式,抽象工厂模式,原型模式,建造者模式
- 结构型模式:适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式
- 行为型模式:模板方法模式,命令模式,访问者模式,迭代器模式,观察者模式,中介者模式,备忘录模式,解释器模式,状态模式,策略模式,责任链模式
单例模式
- 单例模式的解释与使用场景
- 解释:采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
- 使用场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或 耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数 据库或文件的对象(比如数据源、session工厂等)
- 实现方式
- 饿汉式
class Singleton{
//final可以提升一定效率
//类加载时赋值,线程安全
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance(){
return instance;
}
}
- 饿汉式(静态代码块)
class Singleton {
private static Singleton instance;
//静态代码块,在类加载时执行,线程安全
static {
instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance(){
return instance;
}
}
- 懒汉式(线程安全但效率低)
class Singleton {
private static Singleton instance;
private Singleton() {}
//互斥访问共享资源,线程安全。但由于每次获取均需加锁,效率低
public static synchronized Singleton getInstance() {
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
- 懒汉式(线程安全且效率高,DoubleCheck)
class Singleton{
//volatile防止指令重排
private static volatile Singleton instance;
private Singleton() {}
//doubleCheck,规避了效率低且满足线程安全
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
- 静态内部类的方式创建
class Singleton{
private static Singleton instance;
private Singleton() {}
//定义静态内部类,调用内部类创建实例,只有当调用静态内部类时,该内部类才会被创建,从而实现懒加载且线程安全。
private static class SingletonInstance{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonInstance.INSTANCE;
}
}
- 枚举的方式创建(推荐)
public class Singleton06 {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance == instance2);
instance.doSomething();
}
}
enum Singleton{
INSTANCE;
//在枚举类中也可以定义方法
public void doSomething(){
System.out.println("Hello World");
}
}
工厂模式
1. 简单工厂模式
- 案例描述
制作披萨的项目:要便于披萨种类的扩展,要便于维护
- 披萨的种类很多(比如 GreekPizza、CheesePizza 等)
- 披萨的制作有 prepare,bake, cut, box
- 完成披萨店订购功能
- 传统实现方案
- Pizza类
package com.yqj.pattern.factory.simpleFactory.triditional.pizza;
public abstract class Pizza {
//对子类可见,对其他类透明
protected String pizzaName;
public void setPizzaName(String pizzaName) {
this.pizzaName = pizzaName;
}
//由子类实现
public abstract void prepare();
public void bake() {
System.out.println(pizzaName + "烘焙披萨");
}
public void cut() {
System.out.println(pizzaName + "切披萨");
}
public void box() {
System.out.println(pizzaName + "打包披萨");
}
}
- Pizza的子类
// CheesePizza类
package com.yqj.pattern.factory.simpleFactory.triditional.pizza;
public class CheesePizza extends Pizza {
@Override
public void prepare() {
setPizzaName("希腊pizza");
System.out.println(pizzaName+"准备制作");
}
}
// GreekPizza类
package com.yqj.pattern.factory.simpleFactory.triditional.pizza;
public class GreekPizza extends Pizza {
@Override
public void prepare() {
setPizzaName("奶酪pizza");
System.out.println(pizzaName + "准备制作");
}
}
- OrderPizza类,用于定制pizza
package com.yqj.pattern.factory.simpleFactory.triditional.order;
import com.yqj.pattern.factory.simpleFactory.triditional.pizza.CheesePizza;
import com.yqj.pattern.factory.simpleFactory.triditional.pizza.GreekPizza;
import com.yqj.pattern.factory.simpleFactory.triditional.pizza.Pizza;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class OrderPizza {
Pizza pizza = null;
String orderType = null;
//完成定制pizza
public OrderPizza(){
do {
orderType = getOrderType();
if("cheese".equals(orderType)){
pizza = new CheesePizza();
} else if ("greek".equals(orderType)){
pizza = new GreekPizza();
} else {
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
//从终端获取数值
private String getOrderType(){
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type: ");
String orderType = bufferedReader.readLine();
return orderType;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
public static void main(String[] args) {
new OrderPizza();
}
}
- 分析
传统的方式虽然实现了功能,但违背了开闭原则(ocp)。需要扩展功能增加新品类pizza时,会导致调用者代码发生修改。若调用者已创建多个,则当扩展功能时每个调用者的代码均需要修改。不利于软件的扩展性。代码如下:
若此时扩展新品类PepperPizza
// PepperPizza类
package com.yqj.pattern.factory.simpleFactory.triditional.pizza;
public class PepperPizza extends Pizza {
@Override
public void prepare() {
setPizzaName("胡椒pizza");
System.out.println(pizzaName + "准备制作");
}
}
则调用者中的代码也需要修改,新增判断PepperPizza的代码片段
//完成定制pizza
public OrderPizza(){
do {
orderType = getOrderType();
if("cheese".equals(orderType)){
pizza = new CheesePizza();
} else if ("greek".equals(orderType)){
pizza = new GreekPizza();
//修改部分 **************************************************
} else if("pepper".equals(orderType)){
pizza = new PepperPizza();
} else {
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
- 简单工厂模式的解释与使用场景
- 解释:简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,由这个类来封装实例化对象的行为(代码)。
- 使用场景:当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式。
- 改进后的代码
- Pizza类不变
- SimpleFactory工厂类
package com.yqj.pattern.factory.simpleFactory.improve.order;
import com.yqj.pattern.factory.simpleFactory.improve.pizza.CheesePizza;
import com.yqj.pattern.factory.simpleFactory.improve.pizza.GreekPizza;
import com.yqj.pattern.factory.simpleFactory.improve.pizza.Pizza;
//工厂类用于创建实例对象
public class SimpleFactory {
//工厂类负责根据不同的传入参数创建出不同的产品,当需要扩展时,仅在本工厂类中做修改即可,使调用者无需做代码的修改。
public Pizza getFactory(String orderType){
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new CheesePizza();
} else if ("greek".equals(orderType)){
pizza = new GreekPizza();
}
return pizza;
}
}
- OrderPizza类
package com.yqj.pattern.factory.simpleFactory.improve.order;
import com.yqj.pattern.factory.simpleFactory.improve.pizza.CheesePizza;
import com.yqj.pattern.factory.simpleFactory.improve.pizza.GreekPizza;
import com.yqj.pattern.factory.simpleFactory.improve.pizza.Pizza;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class OrderPizza {
Pizza pizza = null;
SimpleFactory factory = null;
public OrderPizza(SimpleFactory factory){
setFactory(factory);
}
public void setFactory(SimpleFactory factory){
this.factory = factory;
String orderType;
do{
orderType = getOrderType();
//使用工厂来获取pizza
pizza = this.factory.getFactory(orderType);
//通过工厂模式创建的实例,完成后续的方法调用
if(pizza != null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("订购披萨失败");
break;
}
}while (true);
}
private String getOrderType(){
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type: ");
String orderType = bufferedReader.readLine();
return orderType;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
public static void main(String[] args) {
new OrderPizza(new SimpleFactory());
}
}
- 分析
使用简单工厂模式,实现了开闭原则。当需要增加新的品类时,不需要修改调用者中的代码,而仅通过修改工厂类中的实例代码即可。实现了较强的扩展性。
- 改进代码(使用静态工厂的方式),进一步简化调用者的代码,无需在类中保存工厂的实例对象。但灵活性降低
- Pizza类不变
- SimpleStaticFactory类 (不变,仅修改类的名字为SimpleStaticFactory)
package com.yqj.pattern.factory.simpleFactory.staticimprove.order;
import com.yqj.pattern.factory.simpleFactory.staticimprove.pizza.CheesePizza;
import com.yqj.pattern.factory.simpleFactory.staticimprove.pizza.GreekPizza;
import com.yqj.pattern.factory.simpleFactory.staticimprove.pizza.Pizza;
public class SimpleStaticFactory {
public static Pizza getFactory(String orderType){
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new CheesePizza();
} else if ("greek".equals(orderType)){
pizza = new GreekPizza();
}
return pizza;
}
}
- OrderFactory类
package com.yqj.pattern.factory.simpleFactory.staticimprove.order;
import com.yqj.pattern.factory.simpleFactory.staticimprove.pizza.Pizza;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class OrderPizza {
Pizza pizza = null;
public OrderPizza(){
setFactory();
}
public void setFactory(){
String orderType;
do{
orderType = getOrderType();
//使用静态工厂的方式创建实例
pizza = SimpleStaticFactory.getFactory(orderType);
if(pizza != null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("订购披萨失败");
break;
}
}while (true);
}
private String getOrderType(){
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type: ");
String orderType = bufferedReader.readLine();
return orderType;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
public static void main(String[] args) {
new OrderPizza();
}
}
2. 工厂方法模式
- 案例需求
客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪pizza、北京的胡椒pizza 或者是伦敦的奶酪pizza、伦敦的胡椒pizza
- 传统方式
使用简单工厂模式,创建不同的简单工厂类,比如:BJPizzaSimpleFactory,LDPizzaFactory等,但若新增加新地点的例如上海pizza时,导致ocp问题。降低软件的可维护性和可扩展性。
- 工厂方法模式
解释:定义一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法模式将对象的实例化推迟到子类中。
- 改进代码
- pizza类
//pizza类
package com.yqj.pattern.factory.factorymethod.pizza;
public abstract class Pizza {
protected String pizzaName;
public void setPizzaName(String pizzaName) {
this.pizzaName = pizzaName;
}
public abstract void prepare();
public void bake() {
System.out.println(pizzaName + "烘焙披萨");
}
public void cut() {
System.out.println(pizzaName + "切披萨");
}
public void box() {
System.out.println(pizzaName + "打包披萨");
}
}
//BJGreekPizza类
package com.yqj.pattern.factory.factorymethod.pizza;
public class BJGreekPizza extends Pizza {
@Override
public void prepare() {
setPizzaName("北京希腊pizza");
System.out.println(pizzaName + "准备制作");
}
}
//BJCheesePizza类
package com.yqj.pattern.factory.factorymethod.pizza;
public class BJCheesePizza extends Pizza {
@Override
public void prepare() {
setPizzaName("北京奶酪pizza");
System.out.println(pizzaName+"准备制作");
}
}
//LDGreekPizza类
package com.yqj.pattern.factory.factorymethod.pizza;
public class LDGreekPizza extends Pizza {
@Override
public void prepare() {
setPizzaName("伦敦希腊pizza");
System.out.println(pizzaName + "准备制作");
}
}
//LDCheesePizza类
package com.yqj.pattern.factory.factorymethod.pizza;
public class LDCheesePizza extends Pizza {
@Override
public void prepare() {
setPizzaName("伦敦奶酪pizza");
System.out.println(pizzaName + "准备制作");
}
}
- order类
package com.yqj.pattern.factory.factorymethod.order;
import com.yqj.pattern.factory.factorymethod.pizza.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
class BJOrderPizza extends OrderPizza{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new BJCheesePizza();
} else if("greek".equals(orderType)){
pizza = new BJGreekPizza();
}
return pizza;
}
}
class LDOrderPizza extends OrderPizza{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new LDCheesePizza();
}else if("greek".equals(orderType)){
pizza = new LDGreekPizza();
}
return pizza;
}
}
public abstract class OrderPizza {
public abstract Pizza createPizza(String orderType);
public OrderPizza(){
Pizza pizza = null;
do{
String orderType = getOrderType();
pizza = createPizza(orderType);
if(pizza!=null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println("订购失败");
break;
}
}while (true);
}
private String getOrderType(){
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type: ");
String orderType = bufferedReader.readLine();
return orderType;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
public static void main(String[] args) {
new BJOrderPizza();
}
}
抽象工厂模式
- 抽象工厂模式
解释:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类。抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。程序员可以 根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇, 更利于代码的维护和扩展。
- 改进代码
-
Pizza类与上面工厂模式的一致
-
Factory类
//AbsFactory类
package com.yqj.pattern.factory.abstractfactory.order;
import com.yqj.pattern.factory.abstractfactory.pizza.Pizza;
public interface AbsFactory {
Pizza createPizza(String orderType);
}
//BJFactory类
package com.yqj.pattern.factory.abstractfactory.order;
import com.yqj.pattern.factory.abstractfactory.pizza.BJCheesePizza;
import com.yqj.pattern.factory.abstractfactory.pizza.BJGreekPizza;
import com.yqj.pattern.factory.abstractfactory.pizza.Pizza;
public class BJFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new BJCheesePizza();
}else if("greek".equals(orderType)){
pizza = new BJGreekPizza();
}
return pizza;
}
}
//LDFactory类
package com.yqj.pattern.factory.abstractfactory.order;
import com.yqj.pattern.factory.abstractfactory.pizza.LDCheesePizza;
import com.yqj.pattern.factory.abstractfactory.pizza.LDGreekPizza;
import com.yqj.pattern.factory.abstractfactory.pizza.Pizza;
public class LDFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new LDCheesePizza();
}else if("greek".equals(orderType)){
pizza = new LDGreekPizza();
}
return pizza;
}
}
- OrderPizza类
package com.yqj.pattern.factory.abstractfactory.order;
import com.yqj.pattern.factory.abstractfactory.pizza.Pizza;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class OrderPizza {
AbsFactory factory;
public OrderPizza(AbsFactory factory){
setFactory(factory);
}
public void setFactory(AbsFactory factory){
this.factory = factory;
Pizza pizza = null;
do{
String orderType = getOrderType();
pizza = this.factory.createPizza(orderType);
if(pizza!=null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("订购失败");
break;
}
}while (true);
}
private String getOrderType(){
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type: ");
String orderType = bufferedReader.readLine();
return orderType;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
public static void main(String[] args) {
new OrderPizza(new BJFactory());
}
}
工厂模式小结
- 工厂模式的意义 将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的 依赖关系的解耦。从而提高项目的扩展和维护性。
- 三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式)
- 设计模式的依赖抽象原则
网友评论