zoukankan      html  css  js  c++  java
  • 设计原则

    1.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起.------分离变化与不变化的部分,框架实际就是把业务与其余不变的代码进行分离,好让程序员更好的进行 if  else 操作.

    2.针对接口编程,不针对实现编程.------面向抽象,不面向具体的实现,代码如果依赖于具体的实现可拓展性比较差,牵一发而动全身.

    java分为编译期和运行期,在编译期如果编写的代码依赖与具体的实现,后期拓展功能会频繁的更改代码.

    但是当编译期依赖于抽象的时候,在运行期会根据传入具体的类型执行代码,所以不需要频繁更改代码.

    举个例子:

    定义一个接口Animal,会发出声音

    public interface Animal {
        void makeSound();
    }

    定义两个具体的类Cat,Dog,实现接口Animal

    public class Cat implements Animal{
    
        @Override
        public void makeSound() {
            System.out.println("喵喵喵");
        }
    
    }
    public class Dog implements Animal{
    
        @Override
        public void makeSound() {
            System.out.println("汪汪汪");
        }
        
    
    }

    编写测试类

    public class AnimalTest {
        
        public static void main(String[] args) {
            Cat cat = new Cat();
            test(cat);
        }
        private static void test(Cat cat) {
            cat.makeSound();
        }
    }

    可以看到,如果test类依赖于具体的cat类型,如果这时候需要传入dog参数,就需要在改写一遍代码如:

    public class AnimalTest {
        
        public static void main(String[] args) {
            Cat cat = new Cat();
            Dog dog = new Dog();
            test(cat);
            test(dog);
        }
        private static void test(Cat cat) {
            cat.makeSound();
        }
        private static void test(Dog dog) {
            dog.makeSound();
        }
    }

    如果后期在有别的动物出现,就需要不停的重载test方法,其实我们这边关心的只是动物发出的声音,完全可以用Animal类来替代具体的类,比如

    public class AnimalTest {
        
        public static void main(String[] args) {
            Cat cat = new Cat();
            Dog dog = new Dog();
            test(cat);
            test(dog);
        }
        private static void test(Animal animal) {
            animal.makeSound();
        }
    //    private static void test(Cat cat) {
    //        cat.makeSound();
    //    }
    //    private static void test(Dog dog) {
    //        dog.makeSound();
    //    }
    }

    这边参数直接声明成Animal接口,在运行期根据传入的具体类型来执行子类的实现方法,这种操作也叫向上转型.

    这样实现的话代码就比较简洁,而且代码拓展性与可维护性也比较好,就算在来100只动物,test类不需要更改.

    3.多用组合,少用继承. ------ 继承会强制子类继承某些不需要的方法或者实现,但是组合的话可以自由添加与删除.继承设计子类是在编译时静态决定,所有子类会具有相同行为.组合能拓展对象的行为,可以在运行时动态拓展.通过组合也能实现代理模式拓展功能,无需修改原来的代码,也符合以下的开闭原则,对于修改关闭.

    4.为了交互对象之间的松耦合设计而努力. ---------还是解耦,降低类与类之间的依赖,只要接口的规定被遵守,整个系统就更有弹性,话说如果需求涉及到接口改变怎么办,这时候估计就考验架构师的功底和经验了.

    5.类应该对拓展开放,对修改关闭.-------理解的话就是字面的意思,在不修改源代码的基础上拓展功能,和代理有点像,但是不应该为了设计而设计,这只是一个原则, 应该在最可能修改的地方应用这些原则,如果大量应用,可能会使项目变得很复杂,要设计的完美,还需要大量的实践,看来编程还是挺吃工作经验的,没几个项目经验设计不出好的项目.

    6.要依赖抽象,不要依赖具体的类(依赖倒置原则).------'依赖'可以理解成实例化一个类,当A的方法或者变量中实例化类B的时候,我们就可以说类A依赖于类B.要想达成依赖倒置原则,就需要依赖于抽象,而不是具体的实现类,画图解释.

    在类A中创建了类B,类C,类D,我们就可以说A依赖于B,C,D,当B,C,D改变的时候或者我们需要在A中增加新的类的时候我们就需要修改A中的代码

    当使用接口或者抽象类的时候,A依赖于抽象类或者接口,因为B,C,D需要实现抽象类或者接口,所以B,C,D依赖于抽象类或者接口,我们可以看到整个样子是呈现出倒置状态,这个时候就是我们所说的依赖倒置.

    这里A就是高层组件,高层组件指的是其他底层组件定义其行为的类,比如A的行为就是B,C,D的方法定义的,所以A是高层组件,B,C,D是低层组件.

    用高层组件和低层组件来解释依赖倒置原则就是:

    不能让高层组件依赖于低层组件,高层组件和低层组件都应该依赖于抽象.

    三个方针来实现这一个目标:

    1.变量不可以持有具体类的引用.

    2.不要让类派生具体类.

    3.不要覆盖基类中已经实现的方法.

    还是老样子,设计模式会增加系统的复杂度和类的数量,过度设计不一定是好事,还是要把握好那个度来达到依赖倒置原则.

    7.最少知识原则.------系统之间的类相互依赖不要太多,外观模式就达到了这一点,通过定义一个中间类,来解耦客户端和系统之间的依赖.

    在平常的编码中,我们应该调用以下对象的方法:

      1.该对象本身

      2.参数传递的对象

      3.方法创建(比如工厂方法)或者实例化的对象

      4.对象的任何组件

    8.好莱坞原则------别找我,我会找你. 用模板方法为例子,底层组件可以通过模板方法倒钩到高层组件上,在高层组件需要的时候直接调用即可.具体参考模板方法.

    spring框架中也应用了这个原则,spring 的 IOC 控制反转就是这个原则,把类的创建以及类于类之间的依赖都交给spring 去维护和管理,当类依赖于另一个类的时候,不需要去向spring申请,而是

     spring 通过 配置 以及 注解 的方式来找到类于类之间的依赖,通过 DI 来进行注入, 所以类和类 之间的依赖通过 用户来定义,整个模块处于一个可控制的范围中.

    9.单一职责原则------一个类应该只有一个引起变化的原因. 虽然这样做会增加类和接口的数量,但是不这么做的话在拓展功能的时候会修改大量代码.

  • 相关阅读:
    IIS代理
    NODEJS
    js图表插件
    注册nodejs程序为windows服务
    中断子系统7_中断出口处理
    Leetcode: Sort List
    jquery 鼠标经过放大图片
    在Tomcat上运行ADF Essentials应用
    简谈HTML5与APP技术应用
    Boost的Serialization和SmartPoint搭配使用
  • 原文地址:https://www.cnblogs.com/lishuaiqi/p/11074933.html
Copyright © 2011-2022 走看看