1.概述

    设计模式最早是出现在建筑领域,1977年,美国著名建筑大师、加利福尼亚大学伯克利分校环境结构中心主任克里斯托夫·亚历山大在他的著作《建筑模式语言:城镇、建筑、构造中描述了一些常见的建筑设计问题,并提出了 253 种关于对城镇、邻里、住宅、花园和房间等进行设计的基本模式。到1990年,软件设计界才开始讨论软件的设计模式,1995年,美国的4位作者共同编著了《设计模式:可复用面向对象软件的基础》,这本书中收录了23中设计模式,设计模式的设计是对面向对象的原则的实际应用,对类的继承,封装及多态的综合应用。设计模式按照其功能可分为创建型,结构型及行为型。

  • 创建型:将对象的创建和使用分离。主要有单例模式,原型,工厂方法、抽象工厂和建造者模式。
  • 结构型:通过类的之间的关系组织成更大的结构。主要有代理、适配器、桥接、装饰、外观、享元、组合模式。
  • 行为型:主要类或对象之间怎么通过相互协作完成单个对象无法完成的功能,以及分配职责。主要有模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器模式。

2.单例模式

    单例模式:一个类通过将构造方法私有,暴露出获取对象的方法,使该类仅仅能够创建一个对象。具体实现方式有懒汉式、饿汉式、枚举方式,懒汉式:比较懒,在调用获取单例对象的时候才去创建类的对象,饿汉式:在类在类加载系统中加载后就被创建了,当调用获取单例对象方法的时候直接获取。

  • 饿汉式
public class HungrySingleton {

    private HungrySingleton(){} //将构造方法私有化,防止别的类实例化该类

    private static final HungrySingleton INSTANCE = new HungrySingleton();
    //创建饿汉式类的对象,并且实例化,该对象会在类加载链接准备阶段置为null,在初始化阶段分配具体的对象

    private static HungrySingleton getInstance(){ //获取饿汉式类的对象 HungrySingleton.getInstance();
        return INSTANCE;
    }

}
  • 懒汉式
public class LazySingleton {
    private LazySingleton(){} //构造方法私有化

    private static volatile LazySingleton instance = null; //volatile保证线程缓存失效,访问主存

    public static LazySingleton getInstance(){
        if (null == instance){ //首先判断instance如果为null的话就进入new 对象逻辑,如果不为null,则直接返回实例
            synchronized (LazySingleton.class){ //抢锁
                if (null == instance){
                    //此再次判断instance是否为null,防止,多个线程进入强锁环节,一个线程获取了锁,创建了对象
                    //然后别的线程获取到了锁然后又重新创建了一次,导致对象重复
                    //加了判断后,即使抢到了锁,仍然判断是否为null,就解决了这个问题。
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

    应用场景

    常被创建而又被销毁:一个类创建多个对象后需要被垃圾收集器清理,如果一个类经常被创建而后被回收,就考虑使用单例模式,这样可以节省内存。如数据库连接池。

生活例子:一个班只有一个班长,一个村只有一个村长,一个省只有一个省长,在java中对这些只有一个对象进行初始化并且赋值的时候,如果生成了多个对象就会导致一个班里可能存在多个班长的情况。

2.工厂模式

    工厂模式:包含简单工厂模式,工厂方法模式,抽象工厂模式。

  • 简单工程模式
        定义一个工厂类,传入字符串,工厂方法中通过字符串判断应该创建什么类,然后返回对象。使用案例:一个大型xml文件中,如果直接映射为一个java类对象可能比较复杂,可以通过将xml文件依据节点信息进行分割成不同部分,然后解析不同的节点,而不同节点对应的java对象的生成就可以使用简单工厂方法,依据节点的名称传入到简单工厂方法中,然后返回java类对象,然后将节点解析出来的数据保存到java对象中,然后将java对象作为entity保存到数据库中。
  • 工厂方法模式:
        通过创建工厂接口,工厂接口中定义返回具体功能的方法,不同的工厂实现工厂接口。在各种框架中,经常使用工厂方法模式,通过工厂类来获取目标类。

    interface IProduct{
        void function();
     }
    
     class Car implements IProduct{
    
         @Override
         public void function() {
             System.out.println("载人");
         }
     }
    
     class MP3 implements IProduct{
    
         @Override
         public void function() {
             System.out.println("听音乐");
         }
     }
    
     interface IFactory{
        IProduct newProduct();
     }
    
     class MusicFactory implements IFactory{
    
         @Override
         public IProduct newProduct() {
             return new MP3();
         }
     }
    
     class CarFactory implements IFactory{
    
         @Override
         public IProduct newProduct() {
             return new Car();
         }
     }
  • 抽象工厂模式
        抽象工程模式仍然定义工厂接口,但接口中定义多个方法,方法返回不同的产品,达到一个工厂能够生产多个产品的功能。

       interface IProduct{
          void function();
       }
    
       class Car implements IProduct{
    
           @Override
           public void function() {
               System.out.println("载人");
           }
       }
    
       class MP3 implements IProduct{
    
           @Override
           public void function() {
               System.out.println("听音乐");
           }
       }
    
       interface IPlant{
          void function();
       }
    
       class Apple implements IPlant{
    
           @Override
           public void function() {
               System.out.println("补充维c,远离医生");
           }
       }
    
       class Peanut implements IPlant{
    
           @Override
           public void function() {
               System.out.println("吃花生");        
           }
       }
    
       interface IFactory{
          IProduct newProduct();
          IPlant newPlant();
       }
    
       class SHCityFactory implements IFactory{
    
           @Override
           public IProduct newProduct() {
               return new MP3();
           }
    
           @Override
           public IPlant newPlant() {
               return new Apple();
           }
       }
    
       class BGCityFactory implements IFactory{
    
           @Override
           public IProduct newProduct() {
               return new Car();
           }
    
           @Override
           public IPlant newPlant() {
               return new Peanut();
           }
       }

    生活例子:一个城市有多个工厂,有饮料厂,电器厂,手机厂等等,而客户有多种需求,有的想要苹果汁和耳机、有的想要iphone手机和空调等等,通过向工厂发出指令得到不同的产品。

3.建设者模式

    当创建一个复杂的对象的时候,并且该对象有多个组件组成,例如一个人由多种器官组成,如鼻子,头发,眉毛,皮肤,手,胳膊,腿等等。建设者模式主要由产品、建设者和指挥者三个角色组成。建设者中定义产品组件具体的定义方法,在指挥者中,传入具体的建设者,并且调用建设者的具体建设方法,返回建设者中的产品对象。


class Good{
    String partA;
    String partB;
    String partC;
    String partD;

    public String getPartA() {
        return partA;
    }

    public void setPartA(String partA) {
        this.partA = partA;
    }

    public String getPartB() {
        return partB;
    }

    public void setPartB(String partB) {
        this.partB = partB;
    }

    public String getPartC() {
        return partC;
    }

    public void setPartC(String partC) {
        this.partC = partC;
    }

    public String getPartD() {
        return partD;
    }

    public void setPartD(String partD) {
        this.partD = partD;
    }
}


abstract class GoodBuilder{

    protected Good good = new Good();

    abstract void setGoodPartA();

    abstract void setGoodPartB();

    abstract void setGoodPartC();

    abstract void setGoodPartD();

    public Good getGood(){
        return this.good;
    }
}

class DesktopBuilder extends GoodBuilder{

    @Override
    void setGoodPartA() {
        super.good.setPartA("desktop-parta");
    }

    @Override
    void setGoodPartB() {
        super.good.setPartB("desktop-partb");
    }

    @Override
    void setGoodPartC() {
        super.good.setPartC("desktop-partc");
    }

    @Override
    void setGoodPartD() {
        super.good.setPartD("desktop-partd");
    }
}

class Diretor{

    private GoodBuilder builder;

    public Diretor(GoodBuilder builder){
        this.builder = builder;
        builder.setGoodPartA();
        builder.setGoodPartB();
        builder.setGoodPartC();
        builder.setGoodPartD();
    }

    public Good getGood(){
        return builder.getGood();
    }
}

class Client {

    public static void main(String[] args) {
        GoodBuilder goodBuilder = new DesktopBuilder();
        Diretor diretor = new Diretor(goodBuilder);
        Good good = goodBuilder.getGood();
        System.out.println(good.getPartA());
    }
}

3.代理模式

代理模式:访问一个对象不是直接访问该对象,而是访问该对象的代理对象,代理对象然后再访问真正的对象。此种操作,能够对访问对象作出限制、增强或者修改等操作。

  • 静态代理
public class StaticProxy {
    public static void main(String[] args) {
        Telephone realTelephone = new RealTelephone();
        Telephone proxy = new ProxyTelephone(realTelephone);
        proxy.call();
    }
}

interface Telephone{
    void call();
}

class RealTelephone implements Telephone{

    @Override
    public void call() {
        System.out.println("打电话啦");
    }
}

class ProxyTelephone implements Telephone{

    private Telephone telephone;

    public ProxyTelephone(Telephone telephone){
        this.telephone = telephone;
    }

    @Override
    public void call() {
        this.preCall();
        telephone.call();
        this.afterCall();
    }

    private void preCall(){
        System.out.println("打电话之前");
    }

    private void afterCall(){
        System.out.println("打电话之后");
    }
}
  • 动态代理(jdk)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;



public class DynamicProxy {
    public static void main(String[] args) {
        StoreOneSellWine storeOneSellWine = new StoreOneSellWine();
        InvocationHandler superMarket = new SuperMarket(storeOneSellWine);
        SellWine proxySellWine = (SellWine) Proxy.newProxyInstance(StoreOneSellWine.class.getClassLoader(), StoreOneSellWine.class.getInterfaces(), superMarket);
        proxySellWine.sell();
    }
}

interface SellWine{
    void sell();
}


class StoreOneSellWine implements SellWine{

    @Override
    public void sell() {
        System.out.println("商家1卖酒");
    }
}

class SuperMarket implements InvocationHandler {

    private Object proxyedClassObject;

    public SuperMarket(Object proxyedClassObject){
        this.proxyedClassObject = proxyedClassObject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.preCall();
        Object result = method.invoke(proxyedClassObject, args);
        this.afterCall();
        return result;
    }

    private void preCall(){
        System.out.println("动态代理调用之前");
    }

    private void afterCall(){
        System.out.println("动态代理调用之后");
    }
}

jdk动态代理源码分析

SellWine proxySellWine = (SellWine) Proxy.newProxyInstance(StoreOneSellWine.class.getClassLoader(), StoreOneSellWine.class.getInterfaces(), superMarket);
--------------------------------------------------------

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone(); 
        //获取StoreOneSellWine.class.getInterfaces()接口的所有类
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs); 
        //返回包含StoreOneSellWine.class.getInterfaces()所有接口的class对象

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            //通过class对象得到构造器
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
            //通过构造器创建新的对象,h为superMarket,实现invocationHandler接口的类
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }
----------------------------------------------
通过SellWine具体实现类,获取该实现类的所有实现的接口信息,然后依据这些接口信息生成特殊的字节码byte[],这个生成方法在ProxyClassFactory类中实现的。

    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;
    //proxyName 为包名+$Proxy+生成的序号,包名为生成动态代理对象所在的包名

    /*
     * Generate the specified proxy class.
     */
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags); //生成byte[]
    try {
        return defineClass0(loader, proxyName,
                            proxyClassFile, 0, proxyClassFile.length);//调用native方法,得到class对象

    生活例子:我要买生活用品,而生活用品是商家生产的,我要购买到,需要到商家指定的超市进行购买,我要买的东西,超市已经给我买好了,这个超市就是我买东西的代理商。

4.模版模式

    当解决某一个问题方法步骤基本上是固定,如工作日一天的基本流程:起床,刷牙,吃饭,坐公交,工作,吃午饭,午休,工作,坐公交,吃饭,睡觉。这个流程中工作的内容会不断的变化,那么就可以定义一个模版类,包含这些基本的流程,并且有一定的实现,当子类需要变化时,再进行具体的实现。

public interface WorkDayInterface {
    void toWork();

    void eatFood();

    void morningWork();

    void rest();

    void afternoonWork();

    void goHome();
}

abstract class WorkDay implements WorkDayInterface{
    public void toWork(){
        System.out.println("坐地铁");
    }

    public void eatFood(){
        System.out.println("喝牛奶");
    }

    public abstract void morningWork();

    public void rest(){
        System.out.println("午睡");
    }

    public abstract void afternoonWork();

    public void goHome(){
        System.out.println("坐地铁");
    }
}

class Monday extends WorkDay{

    @Override
    public void morningWork() {
        System.out.println("调试代码");
    }

    @Override
    public void afternoonWork() {
        System.out.println("调试代码");
    }
}

class Tuesday extends WorkDay{

    @Override
    public void morningWork() {
        System.out.println("编码xx模块");
    }

    @Override
    public void afternoonWork() {
        System.out.println("编码xx模块");
    }
}

5.设计模式的七大原则

  • 单一职责原则
  • 接口隔离原则
  • 依赖倒转原则
    ----- 接口
  • 里斯替换原则
  • 合成复用原则
    ----- 继承
  • 开闭原则
  • 迪米特法则

你若安好便是晴天
82 声望10 粉丝

引用和评论

0 条评论