java之设计模式

一、代理模式

  a、抽象角色(接口):声明真实对象和代理对象的共同接口
  b、代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能替代真实对象相同的接口以便在任何时刻都能替代真实对象。
          同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装
  c、真实角色:代理角色代表的真实对象,是我们最终要应用的对象
1.静态代理:
     由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
   
//接口
public interface UserDAO {
    public void add();
}
//真实角色
public class UserDaoImpl implements UserDAO{
    public void add() {
        System.out.println("添加数据");
    }
}
//代理角色
public class UserDaoImplProxy implements UserDAO{
    private UserDaoImpl userDaoImpl;
    public UserDaoImplProxy(UserDaoImpl userDaoImpl) {
        super();
        this.userDaoImpl = userDaoImpl;
    }
    public void add() {
        log();
        userDaoImpl.add();
        System.out.println("========>add()");
    }
    private void log(){
        System.out.println("添加日志");
    }
}
View Code

2.动态代理

 动态代理:在程序运行时,运用反射机制动态创建而成。

 jdk提供的动态代理

public interface UserDAO {
    public void addUser();
    public void updateUser();
}

public class UserDaoImpl implements UserDAO {
    public void addUser() {
        System.out.println("添加用户");
    }
    public void updateUser() {
        System.out.println("更新用户");
    }
}

public class UserLog {
    public static void beginLog(String methodName ){
        System.out.println(methodName+"方法,开始执行");
    }
}



public class ProxyHandler implements InvocationHandler {
    private Object proxyObject;//
    public ProxyHandler(Object proxyObject){
        this.proxyObject=proxyObject;
    }
    /**
     *  Object proxy:指被代理的对象。 
     *    Method method:要调用的方法 
     *    Object[] args:方法调用时所需要的参数
     */
    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
        System.out.println("proxy:"+proxy.getClass().getName());  
        System.out.println("method:"+method.getName());  
        System.out.println("args:"+args);  
        UserLog.beginLog(method.getName());
        Object object=method.invoke(proxyObject, args);//普通的Java反射代码,通过反射执行某个类的某方法  
        return object;
    }
}

public class TestProxy {
    public static void main(String[] args) {
        testProxy();
    }
    private static void testProxy(){
        UserDaoImpl userDaoImpl=new UserDaoImpl();//元对象(被代理对象)  
        ProxyHandler invocationHandler =new ProxyHandler(userDaoImpl);//代理实例的调用处理程序。 
        //创建一个实现业务接口的代理类,用于访问业务类(见代理模式)。  
       //返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序,如ProxyHandler。  
        UserDAO userDAO= (UserDAO)Proxy.newProxyInstance(
                userDaoImpl.getClass().getClassLoader(),userDaoImpl.getClass().getInterfaces(),
                invocationHandler);  
        //调用代理类方法,Java执行InvocationHandler接口的方法.  
        userDAO.addUser();
    }
}
View Code

 

二、单例模式

        确保一个类只有一个对象

package com.jalja.jdk17.Polymorphic;
/**
 * 
 * 懒汉式
 *  构造器 私有化,避免外部创建对象
 *  声明一个私有的静态变量
 *  创建一个对外公开的静态方法访问该变量,如果没有变量,创建对象
 *
 */
public class JVM {
    private static JVM instance=null;
    private JVM(){
        
    }
    public static JVM getInstances(){
        if(instance==null){
            synchronized (JVM.class) {
                if(instance==null){
                    instance=new JVM();
                }
             }
        }
        return instance;
    }
}
View Code

 三、策略模式

   定义:策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。

         策略模式的组成:     

      抽象策略角色:策略类,通常由一个接口或者抽象类实现。

      具体策略角色:包装了相关的算法和行为。

      环境角色:持有一个策略类的引用,最终给客户端用的。

    优点

      1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。 
      2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。 
      3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

    缺点: 
      1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。

      2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,

        而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)

//抽象策略角色:策略类, 给出所有的具体策略类所需的接口(给具体策略类一个方向)。
public interface Strategy {
    public int calculate(int a,int b);
}

//具体的策略类 一:求和
public class AddStrategy implements Strategy {
    public int calculate(int a, int b) {
        return a+b;
    }
}

//具体 策略类三:相乘
public class MultiplyStrategy implements Strategy{
    public int calculate(int a, int b) {
        return a*b;
    }
}

//具体的策略类 二:相减
public class SubtractStrategy implements Strategy{
    public int calculate(int a, int b) {
        return a-b;
    }
}

//环境角色,持有Strategy接口的引用,并且有get和set方法可以完成策略更换。在环境角色中调用接口的方法完成动作。
public class Environment {
    private Strategy strategy;
    public Environment(Strategy strategy) {
        super();
        this.strategy = strategy;
    }
    public Strategy getStrategy() {
        return strategy;
    }
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    public int calculate(int a, int b){
        return strategy.calculate(a, b);
    }
    //测试
    public static void main(String[] args) {
        // 调用 AddStrategy 求和
        Strategy addStrategy=new AddStrategy();
        Environment environment1=new Environment(addStrategy);
        System.out.println("求和====》"+environment1.calculate(5, 10));
        // 调用 AddStrategy 求积
        Strategy multiplyStrategy=new MultiplyStrategy();
        Environment environment2=new Environment(multiplyStrategy);
        System.out.println("求积===》"+environment2.calculate(5, 10));
        // 调用 AddStrategy 求差
        Strategy subtractStrategy=new SubtractStrategy();
        Environment environment3=new Environment(subtractStrategy);
        System.out.println("求差====》"+environment3.calculate(5, 10));
    }
}
View Code

 四、简单工厂模式

            定义:简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。

package com.jalja.jdk7.test.ms;
//抽象策略角色:策略类, 给出所有的具体策略类所需的接口(给具体策略类一个方向)。
public interface Strategy {
    public int calculate(int a,int b);
}

package com.jalja.jdk7.test.ms;
//具体的策略类 一:求和
public class AddStrategy implements Strategy {
    public int calculate(int a, int b) {
        return a+b;
    }
}

package com.jalja.jdk7.test.ms;
//具体的策略类 二:相减
public class SubtractStrategy implements Strategy{
    public int calculate(int a, int b) {
        return a-b;
    }
}

package com.jalja.jdk7.test.ms;
//具体 策略类三:相乘
public class MultiplyStrategy implements Strategy{
    public int calculate(int a, int b) {
        return a*b;
    }
}

package com.jalja.jdk7.test.ms;
import sun.org.mozilla.javascript.internal.Evaluator;

//环境角色,持有Strategy接口的引用,并且有get和set方法可以完成策略更换。在环境角色中调用接口的方法完成动作。
public class Environment {
    private Strategy strategy;
    public Environment(Strategy strategy) {
        super();
        this.strategy = strategy;
    }
    public Strategy getStrategy() {
        return strategy;
    }
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    public int calculate(int a, int b){
        return strategy.calculate(a, b);
    }
}
package com.jalja.jdk7.test.ms;

public class StrategyFactory {
    private static Strategy strategy;
    public static Strategy getStrategyChile(String objStr){
        if(objStr.equalsIgnoreCase("addStrategy")){
             strategy=new AddStrategy();
        }
        if(objStr.equalsIgnoreCase("multiplyStrategy")){
             strategy=new MultiplyStrategy();
        }
        if(objStr.equalsIgnoreCase("subtractStrategy")){
             strategy=new SubtractStrategy();
        }
        return strategy;
    }
    //利用反射
    public static Strategy getStrategyChile2(String type){
        try {
            strategy=(Strategy) Class.forName("com.jalja.jdk7.test.ms."+type).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return strategy;
    }
    //测试
    public static void main(String[] args) {
        // 调用 AddStrategy 求和
        Environment environment1=new Environment(StrategyFactory.getStrategyChile2("AddStrategy"));
        System.out.println("求和====》"+environment1.calculate(5, 10));
        // 调用 AddStrategy 求积
        Environment environment2=new Environment(StrategyFactory.getStrategyChile2("MultiplyStrategy"));
        System.out.println("求积===》"+environment2.calculate(5, 10));
        // 调用 AddStrategy 求差
        Environment environment3=new Environment(StrategyFactory.getStrategyChile2("SubtractStrategy"));
        System.out.println("求差====》"+environment3.calculate(5, 10));
    }
}
View Code

 五、观察者模式

      定义:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。

          这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。

                   组成:

          抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,

                 可以增加和删除观察者角色。一般用一个抽象类和接口来实现。

          抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。

          具体主题角色:    在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。

          具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。

                  如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。

 1 //抽象观察者角色
 2 public interface Watcher {
 3     public void update(String str);
 4 }
 5 
 6 //抽象主题角色,watched:被观察
 7 public interface Watched {
 8     public void addWatcher(Watcher watcher);
 9     public void removeWatcher(Watcher watcher);
10     public void notifyWatchers(String str);
11 }
12 
13 //具体的观察者
14 public class ConcreteWatcher implements Watcher{
15     private String name;
16     public ConcreteWatcher(String name) {
17         super();
18         this.name = name;
19     }
20     public void update(String str) {
21          System.out.println(name+"收到更新的消息=====》"+str);
22     }
23 }
24 
25 //具体的主题角色: 
26 public class ConcreteWatched implements Watched{
27      // 存放观察者
28     private List<Watcher> list = new ArrayList<Watcher>();
29     public void addWatcher(Watcher watcher) {
30         list.add(watcher);
31     }
32     public void removeWatcher(Watcher watcher) {
33         list.remove(watcher);
34     }
35     public void notifyWatchers(String str) {
36          // 自动调用实际上是主题进行调用的
37         for (Watcher watcher : list)
38         {
39             watcher.update(str);
40         }
41     }
42 }
43 
44 //测试
45 public class Test {
46     public static void main(String[] args) {
47         Watched girl = new ConcreteWatched();//定义主题
48         //创建观察者
49         Watcher watcher1 = new ConcreteWatcher("男一号");
50         Watcher watcher2 = new ConcreteWatcher("男二号");
51         Watcher watcher3 = new ConcreteWatcher("男三号");
52         //主题添加观察者
53         girl.addWatcher(watcher1);
54         girl.addWatcher(watcher2);
55         girl.addWatcher(watcher3);
56         //主题产生最新消息
57         girl.notifyWatchers("开心");
58     }
59 }
View Code

优点

  • 支持松耦合和减少依赖性。客户端不再依赖于观察器,因为通过使用主体和 Observer 接口对客户端进行了隔离。许多框架具有此优点,在这些框架中的应用程序组件可以注册为当(低级)框架事件发生时得到通知。结果,框架将调用应用程序组件,但不会依赖于它。
  • 观察器数目可变。观察器可以在运行时附加和分离,因为主体对于观察器数目没有任何假定。此功能在这样的情况下是很有用的:观察器数在设计时是未知的。例如,如果用户在应用程序中打开的每个窗口都需要一个观察器。

缺点

  • 性能降低。在许多实现中,观察器的 update() 方法可能与主体在同一线程中执行。如果观察器列表很长,则执行 Notify() 方法可能需要很长时间。抽取对象依赖性并不意味着添加观察器对应用程序没有任何影响。
  • 内存泄漏。在 Observer 中使用的回调机制(当对象注册为以后调用时)会产生一个常见的错误,从而导致内存泄漏,甚至是在托管的 C# 代码中。假定观察器超出作用范围,但忘记取消对主体的订阅,那么主体仍然保留对观察器的引用。此引用防止垃圾收集在主体对象也被破坏之前重新分配与观察器关联的内存。如果观察器的生存期比主体的生存期短得多(通常是这种情况),则会导致严重的内存泄漏。
  • 隐藏的依赖项。观察器的使用将显式依赖性(通过方法调用)转变为隐式依赖性(通过观察器)。如果在整个应用程序中广泛地使用观察器,则开发人员几乎不可能通过查看源代码来了解所发生的事情。这样,就使得了解代码更改的含意非常困难。此问题随传播级别急剧增大(例如,充当 Subject 的观察器)。因此,应该仅在少数定义良好的交互(如 Model-View-Controller 模式中模型和视图之间的交互)中使用观察器。最好不要在域对象之间使用观察器。
  • 测试 / 调试困难。尽管松耦合是一项重大的体系结构功能,但是它可以使开发更困难。将两个对象去耦的情况越多,在查看源代码或类的关系图时了解它们之间的依赖性就越难因此,仅当可以安全地忽略两个对象之间的关联时才应该将它们松耦合(例如,如果观察器没有副作用)。

           

       

posted @ 2015-06-17 21:43  小禾点点  阅读(240)  评论(0编辑  收藏  举报