设计模式感想

设计模式的核心就是高类聚,低耦合,这对于代码的扩展性和后期的维护性是大有帮助的(扩展性和维护性指的是修改原来的代码,或者添加新的功能,要是能够在一个好的模式的代码上操作,那将是非常方便的。)

1,工厂模式:掩藏复杂的逻辑过程,只关心结果。常见的工厂模式分为,简单工厂,工厂方法,抽象工厂

抽象工厂虽然代码类有所增加,但是对于客户端而言,调用复杂度大大降低,这就是框架设计者要考虑的关键所在,减少用户调用API的复杂度,这个在spring的BeanFactory 中是怎么体现的呢?

spring 的工厂模式的BeanFactory 是用来生成各种bean的,这个有单例的bean,被代理的bean,最原始的bean,List类型的bean,各种不同作用域的bean,但是我们在使用的时候,获取bean就用一个getBean方法就可以获取想要的bean,不管你是什么样的bean,这样的效果产生就是用了工厂模式的抽象工厂

工厂方法感想:

public class SimpleCarFactory {

    
    public static Car getCar(String name) {
        if("benz".equalsIgnoreCase(name)) {
            return new Benz();
        }else if("bmw".equalsIgnoreCase(name)) {
            return new Bmw();
        }else if("audi".equals(name)) {
            return new Audi();
        }else {
            return null;
        }
    }
}

对于调用端而言还算简单,想要什么车只需要传一个车的名称,但是看下SimpleCarFactory 这个工厂类把所有的车的生产都写在一个getCar的方法中,如果生产每辆车 的逻辑十分复杂的话 ,这个类就会有上万行,维护这个类就成了噩梦,(这就好比用一个servlet类写一个项目,这样实施也是可以的,但是写出来了,估计只有写出来的人看得懂,扩展性维护性完全没有)复杂的逻辑分散在每个if中,这每一个if都是一个生产车的复杂逻辑,造成定位都很难。这就有了演变后的 工厂方法,这个工厂方法是每个造车的都有自己的工厂,造成了类看上去会增多,但是这在实际开发中并没有什么影响,虚拟机也不会因为类变多了,运行效率降低,同时代码的可读性大大提高

public class TestCar {
    public static void main(String[] args) {
        Car car = SimpleCarFactory.getCar("benz");
        System.out.println(car.getName());
    }
}

2,单例模式:保证系统从启动到系统的停止,全过程只产生一个实例。

常见的单例有哪些?(在万千的世界中,即使是一片小小的树叶都是独一无二的)

为什了要有单例?

系统中的配置文件(如果内容一样,造成加载的资源的浪费,有多个也会造成选择性的冲突)

spring的容器ApplicationContext(有多个也没要,造成了资源的浪费)

生活中,公司的直接领导(假如有多个,你就不知到听谁的呢)

这就是我们选择单例的依据标准

单例的写法实际上有七种写法,现在提供一种最为经典的展示一下:(代码没有一句浪费,既能解决安全问题,又能解决性能问题)

//懒汉式(静态内部类的写法)

public class Singleton {
    //1,private 保证别人不能修改,static 保证全局唯一
    private static class LazyHolder{
        private static final Singleton INSTANCE = new Singleton();
    }
    
   //2,将构造器私有化,防止外部调用,//这里说明一点,在反射面前,java的所有信息都是裸奔
    //但是你想实例化我就抛出异常

    private Singleton() {
        throw new RuntimeException("禁止实例化。。");
    }
    
    //3,提供一个静态的方法给外部调用,final 保证别人不能覆盖
    public static final Singleton getInstance() {

//方法中的逻辑是,是在用户调用的时候才开始执行的,方法中实现的逻辑需要分配内存,也是在调用的使用才分配的
        return LazyHolder.INSTANCE;
    }
}

3,委派模式(delegate)(dispatcher)

持有被委派的引用,和代理模式有点像。

类似公司中的项目经理和普通程序员,项目经理分配任务给程序员

,这种模式只关心结果,就好像是,干活是程序员的,功劳是项目经理的

这个和代理模式关心过程是有区别的,

为什么要使用这种模式?

主要是为了掩藏实现细节

IOC容器中,有一个Register的东西(为了告诉我们容器,在这个类初始化的过程中,需要做很多不同的逻辑处理,因此要有多个任务的执行者,分别实现各自的功能,有新的功能,只需要实现这个接口,就可以把功能加进去)

下面举一个例子

public interface IExccutor {

    //定义一个任务的规范
    public void doing();
}

public class ExecutorA implements IExccutor{

    //假设这是一个程序员A完成任务的方法
    public void doing() {
        System.out.println("ExecutorA开始执行任务。。。");
    }

}

public class ExecutorB implements IExccutor{

    //假设这是一个程序员B完成任务的方法
    public void doing() {
        System.out.println("ExecutorB开始执行任务。。。");
    }

}

//假设这是一个项目经理
public class Dispatcher {

    private IExccutor exccutor;
    //持有手下程序员的引用,可以命令去干活
    public Dispatcher(IExccutor exccutor) {
        
        this.exccutor = exccutor;
    }
    
    //这个就好比项目经理开始分配任务
    //表面上干活的是他,其实是他手下的程序员
    //结果就是,干活是你的,功劳是他的

    public void doing() {
        
        this.exccutor.doing();
        
    }
}

public class Test {
    public static void main(String[] args) {
        IExccutor exccutor = new ExecutorA();
        //这个项目经理实际派的是A程序员去干活,表面上看上去是自己在干活
        Dispatcher dis = new Dispatcher(exccutor);
        dis.doing();
    }
}

4,策略模式(strategy)结果是一样的,但是过程是不一样的

什么是策略模式,完成一件事情有多重方式,比如你要去一个地方旅游,你可以选择坐飞机,也可以自己开车去,多种方案可供选择,这些方案就是一种种策略,java 中的比较器就是一个典型的例子

    List<Integer> list = new ArrayList<Integer>();
    Collections.sort(list, new Comparator<Integer>() {

            //返回值0就是相等,返回值1就是前面大于后面
           public int compare(Integer o1, Integer o2) {
                //这里就是一些策略,你可以从大到小,或者从小到大排序
                return 0;
            }
        });
    }

5,原型模式prototype,java中的克隆clone方法就是原型模式的一个典型代表

就是一个现成的对象,这个对象里面已经设置好了值,当我们要创建第二个对象,并且要给这个对象赋值,而且赋值的内容要和先前的一模一样,这种场景下就诞生出 了原型模式

public class User implements Cloneable{
    
    private int age;
    private String name;
    private List<String> friendList;
    
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
   //省略一堆setter/getter

}

测试原型拷贝

public class Test {
    public static void main(String[] args) {
        User user = new User();
        user.setAge(22);
        user.setName("zs");
        List<String> fl = new ArrayList<String>();
        fl.add("wangmazi");
        user.setFriendList(fl);
        
        try {
            /*这个clone 是基于字节码拷贝出来的对象,没有走构造器,所以性能很高
            当前走的是浅拷贝,也就是原始的对象的8个基本类型加上string的内容是完全复制过去了的,但是引用类型,他只是把地址拷贝过去了,造成了拷贝后的对象和原始对象公用的是一个,可能修改拷贝对象造成 了原始对象的数据也会被修改,这是有问题的,所以出现深拷贝解决方案,第二种方案就是利用反射,循环遍历原始的对象的属性一个个拷贝到新的对象中,这当面对原始对象中有大量的字段时,假如有上百个字段,还是可以节省不少事的,但是会有点点的性能问题,(毕竟反射是在运行时的操作),但这个也不是问题,很多ORM框架大量使用这种反射的方式操作很多字段的拷贝,其中Apache Commons Beanutils就有一个操作对象属性批量复制的方法BeanUtils,copyProperties(src,dest)*/

   
            User copy = (User) user.clone();
            System.out.println(user.getFriendList() == copy.getFriendList());//true
            copy.getFriendList().add("wangmazi2");
            System.out.println(user.getFriendList());//[wangmazi, wangmazi2]
            System.out.println(copy.getName()+","+copy.getAge());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值