Java设计模式

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类图

抽象工厂模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值