设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。四位作者合称 GOF(四人帮,全拼 Gang of Four)
1、开闭原则(Open Close Principle)
对扩展开放,对修改关闭。
2、里氏代换原则(Liskov Substitution Principle)
继承必须确保超类所拥有的性质在子类仍然成立。
3、依赖倒转原则(Dependence Inversion Principle)
要面向接口编程,不要面向实现编程。
4、单一职责原则
控制类的粒度大小,将对象解耦,提高其内聚性。
5、接口隔离原则(Interface Segregation Principle)
要为各个类建立它们的专用接口。
6、迪米特法则,(Demeter Principle)
又称最少知道原则:只和你的直接朋友通信,不和陌生人通信。
7、合成复用原则(Composite Reuse Principle)
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。
单例模式(Singleton Pattern)是Java中最简单的设计模式,是一种创建型模式,它提供了一种创建对象的最佳方式,这种模式涉及到一个单一的类来创建对象,同时确保只有一个对象被创建。这个类提供了访问其唯一对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
1、单例类只能有一个实例对象
2、单例类必须自己创建自己的唯一实例
3、单例类必须给其他对象提供该实例
饿汉式
线程安全,比较常用,但容易产生垃圾,因为一开始就初始化,没有加锁,执行效率会提高。
public class Singleton{
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
懒汉式(单线程)
第一次调用,才初始化,避免浪费内存
线程不安全,延迟初始化,没有加锁,在多线程不能正常工作
public class Singleton{
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
懒汉式(多线程下)
第一次调用,才初始化,避免浪费内存
必须加锁 synchronized 才能保证线程安全,但加锁会影响效率
public class Singleton{
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
双重校验锁 DCL(Double Check Locking)多线程安全
双重校验锁写法保证线程安全
使用volatile:保证可见性,禁止指令重排序
线程安全,延迟初始化。这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
public class Singleton{
private volatile static Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
Synchronized(Singleton.class){
//Synchronized保证了原子性
if(singleton == null){
//new对象分解三条指令:前两个指令是new,第三个是 =
//1、分配内存空间
//2、初始化对象
//3、赋值给变量
singleton = new Singleton();
}
}
}
return singleton;
}
}
提供了一种创建对象的最佳方式,在工厂模式中,创建对象时不会对客户端暴露创建逻辑,通过使用一个共同的接口来指向新创建的对象。
实现了创建者和调用者的分离,开闭原则(对扩展开放,对修改关闭),依赖倒转原则(面向接口,不面向实现),迪米特原则(跟直接朋友通信)
简单工厂模式
优点在于实现对象的创建和使用分离,将对象的创建交给专门的工厂类负责,
但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码逻辑将会非常复杂。
车接口,有一个属性name
public interface Car {
void name();
}
特斯拉车
public class Tesla implements Car{
@Override
public void name() {
System.out.println("带翅膀的车");
}
}
五菱宏光
public class WuLing implements Car{
@Override
public void name() {
System.out.println("五菱神车");
}
}
消费者
public class Consumer {
public static void main(String[] args) {
Car car = new WuLing();
Car car1 = new Tesla();
car.name();
car1.name();
}
}
在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。当系统需要新增一个产品是,无需修改现有系统代码,只需要添加一个具体产品类和其对应的工厂子类,使系统的扩展性变得很好,符合面向对象编程的开闭原则。
(在简单工厂的基础上增加了一个车工厂类,消费者不用去关心具体哪个车了,要什么车,直接和工厂说)
加一个车工厂类来实现生产车
车工厂
public class CarFactory {
public Car getCar(String carName){
if(carName.equals("五菱")){
return new WuLing();
}else if(carName.equals("特斯拉")){
return new Tesla();
}else{
return null;
}
}
}
消费者
public class Consumer {
public static void main(String[] args) {
CarFactory carFactory = new CarFactory();
Car car = carFactory.getCar("五菱");
Car car1 = carFactory.getCar("特斯拉");
car.name();
car1.name();
}
}
工厂模式与多态的联系?
多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。每个类都用自己的创建工厂Factory创建自己类型的对象,所有的创建工厂都继承自同一个基类ShapeFactory。在工厂方法模式中,父类负责定义创建对象的公共接口,而子类则负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类。