常见设计模式实例讲解

单例模式的三种实现方式及其优缺点

public class SingletonDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        SingletonEnum.INSTANCE.setmName("enum");
        SingletonInner.getInstance().setmName("inner");
        SingletonDoubleCheck.getInstance().setmName("doubleCheck");
    }

    /*
     * 单例模式考虑点: 
     * 1. 线程安全:Synchronized关键字,Enum,静态内部类 
     * 2. 延迟加载:减少负载和消耗 
     * 3. 自动序列化(Serializable和transient) 
     * 4. 防止反射强行调用构造器
     * 3、4点只有枚举可以实现
     */

    /*
     * 枚举实现单例
     */
    public static enum SingletonEnum {
        INSTANCE;
        private String mName;

        public String getmName() {
            return mName;
        }

        public void setmName(String mName) {
            this.mName = mName;
        }

    }
    /*
     * 双重检查锁:单例模式中需要new的情况非常少,第一层锁可以减少锁的次数
     */
    public static class SingletonDoubleCheck {
        private static volatile SingletonDoubleCheck singleton = null;

        private SingletonDoubleCheck() {
        }

        public static SingletonDoubleCheck getInstance() {
            if (singleton == null) {
                synchronized (SingletonDoubleCheck.class) {
                    if (singleton == null) {
                        singleton = new SingletonDoubleCheck();
                    }
                }
            }
            return singleton;
        }

        private String mName;

        public String getmName() {
            return mName;
        }

        public void setmName(String mName) {
            this.mName = mName;
        }
    }

    /*
     * 内部类方式实现
     */
    public static class SingletonInner {

        private static class Holder {
            private static SingletonInner singleton = new SingletonInner();
        }

        private SingletonInner() {

        }

        public static SingletonInner getInstance() {
            return Holder.singleton;
        }

        private String mName;

        public String getmName() {
            return mName;
        }

        public void setmName(String mName) {
            this.mName = mName;
        }
    }

}

工厂模式实例

观察者模式

  1. 在Java中通过Observable类和Observer接口实现了观察者模式,Observer对象监视着Observable对象的变化,当Observable对象发生变化时,Observer得到通知,就可以进行相应的工作。
  2. Observable类—-程序中的被观察者类需要继承这个类
  3. Observer接口—-观察者接口,观察者需要实现这个接口并重写其中的update()方法
  4. 可以在main函数中通过调用被观察者的addObserver方法添加观察者,当被观察者发生变化时要调用setChanged()方法标记此Observable对象已改变,并调用notifyObservers()通知所有观察者
  5. 自定义代码实现观察者模式:

    // 被观察者接口
    public interface Subject {
        public void registerObserver(Observer o);
        public void removeObserver(Observer o);
        public void notifyAllObservers();
    }
    
    // 观察者接口
    public interface Observer {
        public void update(Subject s);
    }
    
        // 猎头类
         public class HeadHunter implements Subject {
            private ArrayList<Observer> userList;
            private ArrayList<String> jobs;
    
            public HeadHunter(){
                userList = new ArrayList<Observer>();
                jobs = new ArrayList<String>();
            }
    
            @Override
            public void registerObserver(Observer o) {
                userList.add(o);
            }
    
            @Override
            public void removeObserver(Observer o) {}
    
            @Override
            public void notifyAllObservers() {
                for(Observer o: userList){
                    o.update(this);
                }
            }
    
            public void addJob(String job) {
                this.jobs.add(job);
                notifyAllObservers();
            }
    
            public ArrayList<String> getJobs() {
                return jobs;
            }
    
            public String toString(){
                return jobs.toString();
            }
        }
    
    // 求职者类    
    public class JobSeeker implements Observer {
    
        private String name;
    
        public JobSeeker(String name){
            this.name = name;
        }
        @Override
        public void update(Subject s) {
            System.out.println(this.name + " got notified!");
            //print job list
            System.out.println(s);
        }
    }
    
    // 主函数
    public class Main {
        public static void main(String[] args) {
            HeadHunter hh = new HeadHunter();
            hh.registerObserver(new JobSeeker("Mike"));
            hh.registerObserver(new JobSeeker("Chris"));
            hh.registerObserver(new JobSeeker("Jeff"));
    
            //每次添加一个个job,所有找工作人都可以得到通知。
            hh.addJob("Google Job");
            hh.addJob("Yahoo Job");
        }
    }
    

代理模式

  1. 代理模式就是为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
  2. 静态代理 由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
  3. 动态代理 动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
    • java.lang.reflect.Proxy :Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象, 其中newProxyInstance方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
    • java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。每次生成动态代理类对象时都要指定一个对应的调用处理器对象。

适配器模式

  1. 适配器模式:将一个类的接口,转换成客户期望的另外一个接口。适配器让原本接口不兼容的类可以很好的合作;
    两种方式:①类的适配器模式(采用继承实现)②对象适配器(采用对象组合方式实现);
  2. 使用场景
    • 系统需要使用现有的类,而这些类的接口不符合系统的接口。
    • 想要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作
    • 使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。

装饰器模式VS代理模式

  1. 装饰器模式关注于在一个对象上动态的添加方法,是继承关系的一个替代方案;然而代理模式关注于控制对对象的访问,并不提供对象本身的增强功能。
  2. 装饰器模式来说,装饰者和被装饰者都实现同一个接口; 对代理模式来说,代理类和真实处理的类都实现同一个接口
  3. 参考链接

  4. Java动态代理