1. 什么是设计模式
- 设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路,他不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳定性以及安全性的解决方案。
- 1995年,GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了23种设计模式,从此树立了软件设计模式领域的里程碑,人称[GoF设计模式]

2. 学习设计模式的意义
- 设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的的充分理解。
- 正确使用设计模式具有以下优点:
- 可以提高程序员的思维能力、编程能力和设计能力。
- 使面试程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
- 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强
今天分享面试常问的单例模式和工厂模式
一、单例模式
意图:保证一个类仅有一个实例,并提供一个访问他的全局访问点。
主要解决:一个全局使用的类频繁的创建与销毁。
何时使用:当您想控制实例数目节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。
1. 饿汉式单例
//饿汉式单例
public class Hungry{
//可能会浪费空间
private byte[] data1=new byte[1024*1024];
private byte[] data2=new byte[1024*1024];
private byte[] data3=new byte[1024*1024];
private byte[] data4=new byte[1024*1024];
private Hungry(){
}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
}
饿汉式单例由于new一个对象时不是一个原子性操作,即 new一个对象时, java内部会进行更细致的线程操作,则导致在多线程的条件下会不安全
2. 懒汉式单例
//懒汉式单例
public class LazyMan{
private LazyMan(){
}
private volatile static LazyMan lazyMan;
//双重检测模式的懒汉式单例 ,即DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
synchronized(LazyMan.class){
if(lazyMan==null){
lazyMan=new LazyMan();
//不是一个原子性操作
/**
1.分配内存空间
2.执行构造方法,初始化对象
3.把这个对象指向这个空间
123 A
132 B
此时lazyMan还没有完成构造
**/
}
}
}
return lazyMan;
}
//多线程下不安全
//多线程并发
public static void main(String[] args){
for(int i = 0; i < 10; i++){
new Thread(()->{
lazyMan.getInstance();
}).start();
}
}}
3. 内部类实现单例
//静态内部类实现public class Holder{
public static class InnerClass{
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER=new Holder();
}}
二、工厂模式
-
作用:
- 实现了创建者和调用者的分离
- 实例化对象不使用new,用工厂方法替代
- 将选择实现类,创建对象统一管理和控制。从而将调用这跟我们的实现类解耦。
- 实现了创建者和调用者的分离
-
详细分类:
- 简单工厂模式
- 用来生产同一等级结构中的任意产品(对于增加新的产品,需要扩展已有代码)
- 工厂方法模式
- 用来生产同一等级结构中的固定产品(支持增加任意产品)
- 抽象工厂模式
- 围绕一个超级工厂创建其他工厂。该超级工厂称为其他工厂的工厂。
- 简单工厂模式
-
OOP七大原则
- 开闭原则:一个软件的实体应当对扩展开放
- 依赖倒置原则:要针对接口编程,不要针对实现编程
- 迪米特法则:只与你直接的朋友通信,而避免和陌生人通信
1. 简单工厂模式(静态工厂)
某种程度上不符合设计原则,但实际使用最多。
原始方法
public interface Car {
public void name();
}
public class Tesla implements Car{
public void name(){
System.out.println("特斯拉!");
}}
public class WuLing implements Car{
public void name(){
System.out.println("五菱宏光!");
}}
public class Consumer {
public static void main(String[] args) {
// 接口,所有实现类
Car car=new WuLing();
Car car2=new Tesla();
car.name();
car2.name();
// Car car = CarFactory.getCar("五菱");
// car.name();
}}
运行截图

这种方法需要知道所有接口和实现类才能调用
静态工厂方法
因为CarFactory类中的所有方法都是静态的,需要向其中添加参数来返回不同的对象实例。
增加一个新的产品,如果不修改CarFactory代码就做不到。
public class CarFactory {
// 方法一
public static Car getCar(String car){
if(car.equals("五菱")){
return new WuLing();
}else if(car.equals("特斯拉")){
return new Tesla();
}else {
return null;
}
}
// 方法二
public static Car getWuLing(){
return new WuLing();
}
public static Car getTesla(){
return new Tesla();
}}
public class Consumer {
public static void main(String[] args) {
// 接口,所有实现类
// Car car=new WuLing();
// Car car2=new Tesla();
// car.name();
// car2.name();
Car car = CarFactory.getCar("五菱");
Car car2 = CarFactory.getCar("特斯拉");
car.name();
car2.name();
}}
运行截图

图形描述:

代码分析:
- 在这种工厂实现的情况下增加新的产品(类)实现起来会比较复杂。需要修改CarFactory类,因此违反了开闭原则。
- 虽然方法二比方法一添加新的类不需要修改内部逻辑、更加简单,但方法一与方法二本质上都是需要在原来代码的基础上增加新的代码才能添加新的产品(类),依旧不满足不修改原油代码的要求。
2. 工厂方法模式
不修改已有类的前提下,可以增加产品类。
public interface CarFactory {
Car getCar();
}
public class TeslaFactory implements CarFactory {
public Car getCar() {
return new Tesla();
}}
public class WuLingFactory implements CarFactory {
@Override
public Car getCar() {
return new WuLing();
}}
public class Consumer {
public static void main(String[] args) {
Car car = new WuLingFactory().getCar();
Car car1 = new TeslaFactory().getCar();
car.name();
car1.name();
}}
运行截图:

新增一个产品
public class DaZhong implements Car{
@Override
public void name() {
System.out.println("大众!");
}}
public class DaZhongFactory implements CarFactory {
@Override
public Car getCar() {
return new DaZhong();
}}
public class Consumer {
public static void main(String[] args) {
Car car = new WuLingFactory().getCar();
Car car1 = new TeslaFactory().getCar();
car.name();
car1.name();
Car car2 = new DaZhongFactory().getCar();
car2.name();
}}
运行截图:

图形描述:

对比
- 结构复杂度:simple更简单
- 代码复杂度:simple更简单
- 编程复杂度:simple更简单
- 管理上的复杂度:simple更简单
根据设计原则:工厂方法模式
根据实际业务:简单工厂模式
3、抽象工厂模式
-
定义:抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类
-
适用场景:
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的重复代码(一次一起全部创建,很少更改)
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现
-
优点:
- 具体产品在应用层的代码隔离,无需关心创建的细节
- 将一个系列的产品统一到一起创建
-
缺点:
- 规定了所有可能被创建的产品集合,产品簇中扩展新的产品困难;
今天就分享到这里啦