几种设计模式的作用及实现

工厂

工厂模式主要是为了解耦,A类想要调用B类,但是实例化B对象比较复杂,所以我们就把B对象的创建放到工厂里面统一管理。由于B对象的创建已经统一了起来,所以即使业务逻辑发生变化,我们也只需要修改工厂类,而不需要寻找每个创建B对象的地方去修改。

例如,我们项目可能会使用多个数据库源,但是他们的JDBC配置是不同的,所以我们就可以使用工厂模式来统一,也减少了使用者出错的概率。

使用场景:

精确数据计算,获取Jdbc连接,或者类似的通讯连接

实现:

简单工厂:

首先创建一个接口

public interface Operation {
 
    public double getResult(double numberA,double numberB) throws Exception;
 
}

然后是加减乘除的实现类

public class Add implements Operation{
 
    // 加法计算
    public double getResult(double numberA, double numberB) {
 
        return numberA + numberB;
    }
}

// 减  Sub 
// 乘  Mul 
// 除  Div 

然后是简单工厂

public class EasyFactory {
 
    // 简单工厂,根据字符串创建相应的对象
    public static Operation createOperation(String name) {
        Operation operationObj = null;
        switch (name) {
            case "+":
                operationObj = new Add();
                break;
            case "-":
                operationObj = new Sub();
                break;
            case "*":
                operationObj = new Mul();
                break;
            case "/":
                operationObj = new Div();
                break;
        }
        return operationObj;
    }
}

调用:

public class Client {
 
    public static void main(String[] args) throws Exception {
 
        Operation add = EasyFactory.createOperation("+");
        Operation sub = EasyFactory.createOperation("-");
        Operation mul = EasyFactory.createOperation("*");
        Operation div = EasyFactory.createOperation("/");
 
        System.out.println(add.getResult(1, 1));
        System.out.println(sub.getResult(1, 1));
        System.out.println(mul.getResult(1, 1));
        System.out.println(div.getResult(1, 1));
    }
}

工厂模式

工厂方法模式是对简单工厂模式进一步的解耦,因为在工厂方法模式中是一个子类对应一个工厂类,而这些工厂类都实现于一个抽象接口。这相当于是把原本会因为业务代码而庞大的简单工厂类,拆分成了一个个的工厂类,这样代码就不会都耦合在同一个类里了。

实现:

首先定义工厂接口:

import com.ljy.Mode.Operation;
 
public interface Factory {
 
    public Operation createOperation() ;
 
}

然后是工厂实现类

// 加法类工厂
public class AddFactory implements Factory{
 
    public Operation createOperation() {
        System.out.println("加法运算");
        return new Add();
    }
}
 
// 减法类工厂
public class SubFactory implements Factory{
 
    public Operation createOperation() {
        System.out.println("减法运算");
        return new Sub();
    }
}
........

调用:

public class Client {
 
    public static void main(String[] args) throws Exception {
 
        // 使用反射机制实例化工厂对象,因为字符串是可以通过变量改变的
        Factory addFactory = (Factory) Class.forName("com.ljy.mode.factory.AddFactory").newInstance();
        Factory subFactory=(Factory) Class.forName("com.ljy.mode.factory.SubFactory").newInstance();
 
        // 通过工厂对象创建相应的实例对象
        Operation add = addFactory.createOperation();
        Operation sub = subFactory.createOperation();
 
        System.out.println(add.getResult(1, 1));
        System.out.println(sub.getResult(1, 1));
    }
}

抽象工厂模式

抽象工厂与工厂方法模式的区别在于:抽象工厂是可以生产多个产品的,它围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。

说白了,就是创建一个抽象工厂,然后建立其他工厂类实现。

实现就不写了 有点麻烦,以后补充。

单例

单例设计模式,就是有一个准则,那就是只有一个对象被创建!!!,而且单例也是最简单的设计模式了

单例模式的作用很明显,首先,节省内存,因为我只有一个对象,其次,我能保证数据的唯一性。

为了保证对象唯一性,所以我们首先要确定构造方法的私有性,这样的话就不能通过new的方式创建对象了,然后我们可以在内部创建自身对象,但是对象必须是私有的,然后,我们需要一个静态的公开的方法,来让外部类获取对象。

饿汉模式

饿汉,一直在叫着“我好饿啊”,啥都想吃,所以,这种设计模式,是在一开始就已经把对象创建好了,但是,会造成内存浪费啊,就算没用到他,也会在哪里占着浪费内存。

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
        return instance;  
    }  
}

懒汉模式

懒汉啥样的,那当然是懒啊,所以懒汉模式,就意味着,只有等到需要这个对象的时候,才回去创建对象

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 singleton;  
    private Singleton (){}  
    public static synchronized Singleton getSingleton() {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        return singleton;  
    }  
}

但是加锁一时爽,效率太差了啊,那么多线程都在方法外面等着呢啊

饿汉模式(双重检查)

既然加锁方法会造成效率低下,那咱们就把加锁的位置改一下吧,放在方法里面

public class Singleton {  
    private static Singleton singleton;  
    private Singleton (){}  
    public static synchronized Singleton getSingleton() {  
        if (singleton == null) {  
            synchronized (Singleton.class) {  
                if (singleton == null) {  
                    singleton = new Singleton();  
                }  
            }  
        }  
        return singleton;  
    }  
}

但是,一想想,不对啊  这样还是会造成线程不安全啊,导致出现两个对象啊,不行不行,那咋办呢  要不再加个锁?可是锁加在哪里呢?

饿汉模式(双重锁)

于是,我们就加了个锁,将这个锁加载了声明对象的时候,使用了volatile,这个版本也是非常完美的版本的,面试推荐哦

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
        if (singleton == null) {  
            synchronized (Singleton.class) {  
                if (singleton == null) {  
                    singleton = new Singleton();  
                }  
            }  
        }  
        return singleton;  
    }  
}

那么我们总想着懒汉饿汉,是不是还有其他方式呢(注意,上面任意一种方式,都是无法阻止反射的!!!或者通过序列化 ,我们也是可以获得两个对象),其实是有的,那就是枚举,枚举是天生的单例,而且可以阻止反射哦

枚举

public enum  EnumSingleton {
    INSTANCE;
    public EnumSingleton getInstance(){
        return INSTANCE;
    }
}

看,是不是,非常简单,代码量也很少

装饰器

装饰器模式的定义是允许向一个现有的对象添加新的功能,同时又不改变其结构。就像是,我下个单,中间可能会有打折,可能会有运费,价格就会变动,所以我们就可以通过装饰器模式来实现。

至于实现的话,其实也是主要靠继承子类重写父类方法的原理来实现

首先一个接口是肯定的了:

public interface Component {
	public void biu();
}

然后接口实现类:

public class ConcretComponent implements Component {

	public void biu() {
        
        System.out.println("biubiubiu");
    }
}

接下来是装饰器的接口:

//装饰类
public class Decorator implements Component {

  public Component component;
  
  public Decorator(Component component) {
      
      this.component = component;
  }
  
  public void biu() {
      
      this.component.biu();
  }
}

最后就是装饰器接口实现类:

//具体装饰类
public class ConcreteDecorator extends Decorator {

  public ConcreteDecorator(Component component) {
      super(component);
  }
  public void biu() {
      System.out.println("fire in the hole");
      this.component.biu();
  }
}

说白了是不是感觉很简单的,不就是多态么。

具体调用是这样的:

public class Client {
	public static void main(String[] args) {
		//使用装饰器
		Component component = new ConcreteDecorator(new ConcretComponent());
		component.biu();
	}
}

代理

代理,一说起代理我们就可以联想到代理商,代理商干嘛的,那不就是帮助别人做事的么,例如什么猎头啊,中介啊,类似的,都是代理的体现。而且我们还可以借助代理类再次增加一些功能,而不需要修改原有代码。符合开闭原则

至于到项目开发中,我们总会遇见一些事情,是我们不想让我们的实现类实现的,例如,日志啊,缓存啊,我们想在这个实现类执行的前后执行另外的一些操作,这就用到了我们的代理模式了。

同时代理模式和装饰器模式是不一样的!!!。

装饰器模式和代理模式的区别:

装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。

代理分为静态代理动态代理。

静态代理

静态代理是在运行前,代理类的class文件就已经创建好了。但是呢,静态代理也有缺点,我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。 

首先是接口:

package com.ljy.util.designMode.proxy;

public interface BuyHouse {
    void buyHosue();
}

然后是实现类:

package com.ljy.util.designMode.proxy;

public class BuyHouseImpl implements BuyHouse {

    @Override
    public void buyHosue() {
        System.out.println("我要买房");
    }
}

然后就是静态代理类:

package com.ljy.util.designMode.proxy;

public class BuyHouseProxy implements BuyHouse {

    private BuyHouse buyHouse;

    public BuyHouseProxy(final BuyHouse buyHouse) {
        this.buyHouse = buyHouse;
    }

    @Override
    public void buyHosue() {
        System.out.println("买房前准备");
        buyHouse.buyHosue();
        System.out.println("买房后装修");

    }
}

最后是测试类:

package com.ljy.util.designMode.proxy;

public class ProxyTest {
    public static void main(String[] args) {
        BuyHouse buyHouse = new BuyHouseImpl();
        buyHouse.buyHosue();
        BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);
        buyHouseProxy.buyHosue();
    }
}

动态代理

动态代理是在程序运行时通过反射机制动态创建的。

在动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK再运行时为我们动态的来创建。

首先让我们创建动态代理类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDKDynamicProxy
 * jdkd动态代理
 *
 * @author
 * @create 2018-03-29 16:17
 **/
public class JDKDynamicProxy implements InvocationHandler { // 一定要实现这个类哦

    private Object target;

    public JDKDynamicProxy(Object target) {
        this.target = target;
    }

    /**
     * 获取被代理接口实例对象
     * @param <T>
     * @return
     */
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("买房前准备");
        Object result = method.invoke(target, args);
        System.out.println("买房后准备");
        return result;
    }
}

然后就是测试类:

package com.ljy.util.designMode.proxy.dynamic;

import com.ljy.util.designMode.proxy.BuyHouse;
import com.ljy.util.designMode.proxy.BuyHouseImpl;

/**
 * Client
 * client测试代码
 **/
public class Client {
    public static void main(String[] args) {
        // 将JDK动态代理生成的class文件保存到本地
//        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true"); // 或者是这个

        // jdk动态代理测试
    	BuyHouse buyHouse = new JDKDynamicProxy(new BuyHouseImpl()).getProxy();
    	buyHouse.buyHosue();
    }
}

是不是,只需要一个动态代理类就可以实现了,还不需要针对每个实现类开发。

 


未完待续。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值