7大设计原则
- 单一职责原则
- 里氏替换原则
- 依赖倒置原则
- 开闭原则
- 迪米特法则(最少知道原则)
- 接口隔离原则
- 组合优于继承原则
23种设计模式
单例模式
懒汉式
class LazySingleton{
private static LazySingleton instance;
private LazySingleton(){}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
public static void main(String[] args) {
LazySingleton instance = LazySingleton.getInstance();
LazySingleton instance1 = LazySingleton.getInstance();
System.out.println(instance1 == instance);//true
}
多线程情况下:
class LazySingleton{
private static LazySingleton instance;
private LazySingleton(){}
public static LazySingleton getInstance() {
if (instance == null) {
try {
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
instance = new LazySingleton();
}
return instance;
}
}
public class LazySingletonTest {
public static void main(String[] args) {
new Thread(()->{
LazySingleton instance3 = LazySingleton.getInstance();
System.out.println(instance3);
}).start();
new Thread(() ->{
LazySingleton instance4 = LazySingleton.getInstance();
System.out.println(instance4);
}).start();
}
}
结果:
com.junrui.designpattern.singleton.LazySingleton@90472a2
com.junrui.designpattern.singleton.LazySingleton@1e057600
给方法加上锁之后
public static synchronized LazySingleton getInstance(){
if (instance == null) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
instance = new LazySingleton();
}
return instance;
}
new Thread(()->{
LazySingleton instance3 = LazySingleton.getInstance();
System.out.println(instance3);
}).start();
new Thread(() ->{
LazySingleton instance4 = LazySingleton.getInstance();
System.out.println(instance4);
}).start();
结果:
com.junrui.designpattern.singleton.LazySingleton@19281561
com.junrui.designpattern.singleton.LazySingleton@19281561
给方法上面添加锁,锁的力度大性能差,然后在创建实例的时候,加锁
public static LazySingleton getInstance(){
if (instance == null) {
synchronized (LazySingleton.class){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
instance = new LazySingleton();
}
}
return instance;
}
new Thread(()->{
LazySingleton instance3 = LazySingleton.getInstance();
System.out.println(instance3);
}).start();
new Thread(() ->{
LazySingleton instance4 = LazySingleton.getInstance();
System.out.println(instance4);
}).start();
结果:
com.junrui.designpattern.singleton.LazySingleton@4388eabf
com.junrui.designpattern.singleton.LazySingleton@626213bf
在给创建对象时加锁的同时,判断对象是否为空,双重判断
public static LazySingleton getInstance(){
if (instance == null) {
synchronized (LazySingleton.class){
if(null == instance){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
instance = new LazySingleton();
}
}
}
return instance;
}
new Thread(()->{
LazySingleton instance3 = LazySingleton.getInstance();
System.out.println(instance3);
}).start();
new Thread(() ->{
LazySingleton instance4 = LazySingleton.getInstance();
System.out.println(instance4);
}).start();
结果:
com.junrui.designpattern.singleton.LazySingleton@4388eabf
com.junrui.designpattern.singleton.LazySingleton@4388eabf
volatile:禁止指令重排。创建对象正常的步骤为:1.分配空间;2.初始化;3.引用赋值,但是由于jit(编译器)或者CPU会对创建对象顺序进行优化,导致初始化和赋值的顺序颠倒。当第一个线程在132的过程中执行到了3,2还没有执行,第二个线程获取到了第一个线程执行到3,2还没有执行的对象 然后就返回了一个缺少初始化的对象,最后导致空指针。所以安全的代码需要加上volatile:使创建对象的顺序必须是 123.
class LazySingleton{
private static volatile LazySingleton instance;
private LazySingleton(){}
public static LazySingleton getInstance(){
if (instance == null) {
synchronized (LazySingleton.class){
if(null == instance){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
instance = new LazySingleton();
}
}
}
return instance;
}
}
new Thread(()->{
LazySingleton instance3 = LazySingleton.getInstance();
System.out.println(instance3);
}).start();
new Thread(() ->{
LazySingleton instance4 = LazySingleton.getInstance();
System.out.println(instance4);
}).start();
饿汉式
静态变量在类加载的初始化阶段就完成了实例的初始化。本质上是借助jvm类加载机制,保证实例的唯一性。
类加载过程:
1.加载二进制数据到内存中,生成对应的class数据结构
2.链接:a.验证;b.准备(给类的静态成员变量赋默认值);c.解析(符号引号转为直接引用)
3.初始化:给类的静态变量赋初值
只有真正使用对应的类时,才会触发初始化 如(当前启动类即main函数所在类,直接进行new
操作,访问静态属性、访问静态方法,用反射访问类,初始化一个子类等等)
public class HungrySingletonTest {
public static void main(String[] args) {
HungrySingleton instance = HungrySingleton.getInstance();
HungrySingleton instance2 = HungrySingleton.getInstance();
System.out.println(instance2 == instance);//true
}
}
class HungrySingleton{
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return instance;
}
}
静态内部类
本质上是利用jvm类加载机制来保证线程安全
只有在实际使用时才会触发类的初始化,所以也是懒加载的一种。
当执行getInstance()方法时去初始化 InnerClassHolder静态内部类
public class InnerClassSingletonTest {
public static void main(String[] args) {
InnerClassSingleton instance1 = InnerClassSingleton.getInstance();
InnerClassSingleton instance2 = InnerClassSingleton.getInstance();
System.out.println(instance2 == instance1);//true
new Thread(() ->{
InnerClassSingleton instance3 = InnerClassSingleton.getInstance();
System.out.println(instance3);
}).start();
new Thread(() ->{
InnerClassSingleton instance4 = InnerClassSingleton.getInstance();
System.out.println(instance4);
}).start();
}
}
class InnerClassSingleton{
private static class InnerClassHolder{
private static InnerClassSingleton instance = new InnerClassSingleton();
}
private InnerClassSingleton(){}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
}
结果:
com.junrui.designpattern.singleton.InnerClassSingleton@90472a2
com.junrui.designpattern.singleton.InnerClassSingleton@90472a2
枚举
public enum EnumSingleton {
INSTANCE;
private void print(){
System.out.println(this.hashCode());
}
}
class EnumTest{
public static void main(String[] args) {
EnumSingleton instance1 = EnumSingleton.INSTANCE;
EnumSingleton instance2 = EnumSingleton.INSTANCE;
System.out.println(instance2 == instance1);//true
}
}
反序列化
反序列化违反单例模式
public class InnerClassSingletonTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
InnerClassSingleton instance1 = InnerClassSingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get("testSerializable")));
oos.writeObject(instance1);
oos.close();
ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get("testSerializable")));
InnerClassSingleton instance2 = ((InnerClassSingleton) ois.readObject());
System.out.println(instance2 == instance1);//false
}
}
class InnerClassSingleton implements Serializable {
static final long serialVersionUID = 42L;
private static class InnerClassHolder{
private static InnerClassSingleton instance = new InnerClassSingleton();
}
private InnerClassSingleton(){}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
}
在反序列化类里面添加Object readResolve()方法,就可以解决
public class InnerClassSingletonTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
InnerClassSingleton instance1 = InnerClassSingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get("testSerializable")));
oos.writeObject(instance1);
oos.close();
ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get("testSerializable")));
InnerClassSingleton instance2 = ((InnerClassSingleton) ois.readObject());
System.out.println(instance2 == instance1);//true
}
}
class InnerClassSingleton implements Serializable {
static final long serialVersionUID = 42L;
private static class InnerClassHolder{
private static InnerClassSingleton instance = new InnerClassSingleton();
}
private InnerClassSingleton(){}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
Object readResolve() throws ObjectStreamException{
return InnerClassHolder.instance;
}
}
工厂方法模式
简单工厂
这是没有使用工厂的方法,当服务端类 Hamburger换成Hamburger2后客户端也得跟着换成Hamburger2,客户端就受到了服务端的影响,耦合度高,违反开闭原则。
//客户端
public class SimpleFactory {
public static void main(String[] args) {
Food food = new Hamburger();
food.eat();
}
}
//===============服务端==================================
interface Food{
public void eat();
}
class Hamburger implements Food{
@Override
public void eat() {
System.out.println("吃汉堡包");
}
}
class RiceNoodle implements Food{
@Override
public void eat() {
System.out.println("吃过桥米线");
}
}
使用简单工厂后,服务端改变后,不影响客户端的正常使用,耦合度低
public class SimpleFactory {
public static void main(String[] args) {
Food hamburger = FoodFactory.getGetFood(1);
Food riceNoodle = FoodFactory.getGetFood(2);
hamburger.eat();
riceNoodle.eat();
}
}
interface Food{
public void eat();
}
class Hamburger implements Food{
@Override
public void eat() {
System.out.println("吃汉堡包");
}
}
class RiceNoodle implements Food{
@Override
public void eat() {
System.out.println("吃过桥米线");
}
}
class FoodFactory{
static Food getGetFood(int type){
Food food = null;
switch (type){
case 1 :
food = new Hamburger();
break;
case 2 :
food = new RiceNoodle();
break;
default : break;
}
return food;
}
}
优点:
1.把具体产品的类型从客户端代码中解耦出来。
2.服务端如果修改了具体的产品类名,客户端也知道。
缺点:
1.客户端不得不记住常量和具体产品的映射关系,比如:1对应汉堡包,2对应米线
2.如果具体产品特别多那么简单工厂就会变得非常臃肿,比如有100个具体产品,则需要在简单工厂中的Switch中写100个case。
3.最重要的是,如果需求有变化,客户端需要扩展具体产品的时候,则需要修改服务端简单工厂中的代码,违反“开闭原则”
工厂方法设计模式
public class Factory {
public static void main(String[] args) {
FoodFactory hamburgerFactory = new HamburgerFactory();
Food hamburger = hamburgerFactory.getFood();
hamburger.eat();
FoodFactory riceNoodleFactory = new RiceNoodleFactory();
Food riceNoodle = riceNoodleFactory.getFood();
riceNoodle.eat();
}
}
interface Food{
public void eat();
}
class Hamburger implements Food {
@Override
public void eat() {
System.out.println("吃汉堡包");
}
}
class RiceNoodle implements Food {
@Override
public void eat() {
System.out.println("吃过桥米线");
}
}
interface FoodFactory{
public Food getFood();
}
class HamburgerFactory implements FoodFactory{
@Override
public Food getFood() {
return new Hamburger();
}
}
class RiceNoodleFactory implements FoodFactory{
@Override
public Food getFood() {
return new RiceNoodle();
}
}
当客户端想扩展时,只需要客户端操作就可以
//================客户端=============
public class Factory {
public static void main(String[] args) {
FoodFactory hamburgerFactory = new HamburgerFactory();
Food hamburger = hamburgerFactory.getFood();
hamburger.eat();
FoodFactory riceNoodleFactory = new RiceNoodleFactory();
Food riceNoodle = riceNoodleFactory.getFood();
riceNoodle.eat();
LpFactory lpFactory = new LpFactory();
Food food = lpFactory.getFood();
food.eat();
}
}
class LpFactory implements FoodFactory{
@Override
public Food getFood() {
return new Lp();
}
}
class Lp implements Food{
@Override
public void eat() {
System.out.println("西安凉皮真好吃");
}
}
//=========================服务端========================
interface Food{
public void eat();
}
class Hamburger implements Food {
@Override
public void eat() {
System.out.println("吃汉堡包");
}
}
class RiceNoodle implements Food {
@Override
public void eat() {
System.out.println("吃过桥米线");
}
}
interface FoodFactory{
public Food getFood();
}
class HamburgerFactory implements FoodFactory{
@Override
public Food getFood() {
return new Hamburger();
}
}
class RiceNoodleFactory implements FoodFactory{
@Override
public Food getFood() {
return new RiceNoodle();
}
}
优点:
1.仍然具有简单工厂的优点,服务器端修改了具体的产品的类名以后,并不会影响到客户端。
2.当客户端需要扩展一个新的产品时,不需要修改服务器端的代码,只需要在客户端扩展一个新的工厂。
缺点:
如果有多个产品等级(Food就是一个产品等级),那么工厂类的数量就会爆炸式的增长。
工厂的名字是视为接口的,作者需要保证对外暴露的接口的名字是稳定的。也就是说,虽然客户端依赖于工厂的类名,但是工厂的名字都是趋向于稳定的。
既然新的产品时客户端扩展的,为什么不直接实例化对象?为什么需要让服务端去帮忙实现?
答:因为服务端在开发功能时不仅仅只会开发一些抽象产品、具体产品、对应的工厂,还会配套一些提前做好的框架。例如:
//================客户端=============
public class Factory {
public static void main(String[] args) {
FoodFactory hamburgerFactory = new HamburgerFactory();
Food hamburger = hamburgerFactory.getFood();
hamburger.eat();
FoodFactory riceNoodleFactory = new RiceNoodleFactory();
Food riceNoodle = riceNoodleFactory.getFood();
riceNoodle.eat();
LpFactory lpFactory = new LpFactory();
Food lp = lpFactory.getFood();
lp.eat();
Business.taste(lpFactory);//Business方法为服务端中配套的框架,如果客户端新的产品是客户端自己创建的,而不是通过服务端创建的,那么就没法使用服务端配套的框架
}
}
class LpFactory implements FoodFactory{
@Override
public Food getFood() {
return new Lp();
}
}
class Lp implements Food{
@Override
public void eat() {
System.out.println("西安凉皮真好吃");
}
}
//=========================服务端========================
interface Food{
public void eat();
}
class Hamburger implements Food {
@Override
public void eat() {
System.out.println("吃汉堡包");
}
}
class RiceNoodle implements Food {
@Override
public void eat() {
System.out.println("吃过桥米线");
}
}
interface FoodFactory{
public Food getFood();
}
class HamburgerFactory implements FoodFactory{
@Override
public Food getFood() {
return new Hamburger();
}
}
class RiceNoodleFactory implements FoodFactory{
@Override
public Food getFood() {
return new RiceNoodle();
}
}
class Business{
public static void taste(FoodFactory factory){
Food food = factory.getFood();
System.out.println("评委1,品尝");
food.eat();
Food food1 = factory.getFood();
System.out.println("评委1,品尝");
food1.eat();
Food food2 = factory.getFood();
System.out.println("评委1,品尝");
food2.eat();
}
}
uml类图
抽象工厂模式