常用设计模式总结(单例模式,工厂模式,代理模式)

常用设计模式总结(未完待续)
单例模式
单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。
单例模式作用:
  1.控制资源的使用,通过线程同步来控制资源的并发访问。
  2.控制实例产生的数量,达到节约资源的目的。
  3.作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。
单例模式应用场景:

  1. Windows的Task Manager(任务管理器)就是很典型的单例模式。
  2. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
  3. 网站的计数器,一般也是采用单例模式实现,否则难以同步。
  4. 应用程序的日志应用,一般都用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
  5. Web应用的配置对象的读取,一般也应用单例模式。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。
  6. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
  7. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
    注:单例模式应用的场景一般发现在以下条件下:
      (1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
      (2)控制资源的情况下,方便资源之间的互相通信。如线程池等。

第一种(懒汉,线程不安全)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
  return instance;
}
}
第二种(懒汉,线程安全)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
   return instance;
}
}
第三种(饿汉)
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
   return instance;
}
}

简单工厂模式,工厂方法模式,抽象工厂模式
1. 简单工厂模式(概要:(1) 一个抽象产品类 (2) 具体产品类 (3)一个工厂)
工厂是一个简单的类,不是抽象类或者是接口,其中生成返回具体产品通常使用if-else或者swith-case。
返回产品的方法一般都是static,所有也称之为静态工厂方法模式(Static FactoryMethod Pattern)。
优点:简单易于实现,把类的实例化交给工厂,易于解耦 。
缺点:添加具体产品需要修改工厂违反OCP开放封闭原则。

2. 工厂方法模式(概要:(1)一个抽象产品类 (2) 多个具体产品类 (3)一个抽象工厂 (4) 多个具体工厂 - 每一个具体产品对应一个具体工厂)
定义一个用来创建对象的接口,但让子类决定实例化哪一个类,工厂方法让类把实例化推迟到了子类。
优点:(1)易于扩展,降低了代码耦合度,对象的生成交给子类去完成。
(2)实现了开放封闭原则,每次添加子产品不需要修改原有代码(假如该工厂又有新的产品要生产,那么只需要创建相应的工厂类和产品类去实现抽象工厂接口和抽象产品接口即可)。
缺点:(1)增加了代码量,每个具体产品都需要一个具体工厂。
(2)当增加抽象产品,也就是添加一个其他产品族,需要修改工厂,也违背了OCP。

3. 抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
理解:当工厂只生产一个产品的时候,即为工厂方法模式,而工厂如果生产两个或以上的商品即变为抽象工厂模式。
优点:(1)代码解耦
(2)实现多个产品族(相关联产品组成的家族),而工厂方法模式的单个产品,可以满足更多的生产需求。
(3)很好的满足OCP开放封闭原则。
(4)抽象工厂模式中我们可以定义实现不止一个接口,一个工厂也可以生产不止一个产品类。
缺点:(1)扩展产品族相当麻烦,而且扩展产品族会违反OCP,因为要修改所有的工厂。
(2)由于抽象工厂模式是工厂方法模式的扩展,总体的来说很笨重。

总结:
简单工厂模式是由一个具体的类去创建其他类的实例,父类是相同的,父类是具体的。
工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成。
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。

代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。(比如,同学代买火车票,寻求律师打官司)

静态代理
具体代码实现如下:
interface Subject {
void request();
}
class RealSubject implements Subject {
public void request(){
System.out.println(“RealSubject”);
}
}
class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println(“begin”);
subject.request();
System.out.println(“end”);
}
}
public class ProxyTest {
public static void main(String args[]) {
RealSubject subject = new RealSubject();
Proxy p = new Proxy(subject);
p.request();
}
}
静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。
**总结:**通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是RealSubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。

动态代理
动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。
其步骤如下:

  1. 编写一个委托类的接口,即静态代理的(Subject接口)

  2. 实现一个真正的委托类,即静态代理的(RealSubject类)

  3. 创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法

  4. 在测试类中,生成动态代理的对象。
    第一,二步骤,和静态代理一样,第三步,代码如下:
    public class DynamicProxy implements InvocationHandler {
    private Object object;
    public DynamicProxy(Object object) {
    this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object result = method.invoke(object, args);
    return result;
    }
    }
    第四步,创建动态代理的对象
    Subject realSubject = new RealSubject();
    DynamicProxy proxy = new DynamicProxy(realSubject);
    ClassLoader classLoader = realSubject.getClass().getClassLoader();//获取委托类的类加载器信息
    Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, proxy);
    subject.visit();
    调用Proxy类的静态方法newProxyInstance即可,该方法会返回代理类对象
    static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
    接收的三个参数依次为:
    ClassLoader loader:指定当前目标对象使用类加载器,写法固定
    Class<?>[] interfaces:目标对象实现的接口的类型,写法固定
    InvocationHandler h:事件处理接口,需传入一个实现类,一般直接使用匿名内部类

总结:
通过反射类Proxy和InvocationHandler回调接口实现的jdk动态代理,要求委托类必须实现一个接口,但事实上并不是所有类都有接口,对于没有实现接口的类,便无法使用该方式实现动态代理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值