• 设计模式(总起式:六大原则)


    完整代码见github:https://github.com/BenMario315/design-patterns

    常用的设计模式可概括为23中,根据其特点可分类为三大类型:
        一、创建型:1.单例模式,2.工厂方法模式,3.抽象工厂模式,4.建造者模式,5.原型模式
        二、结构型:6.代理模式,7.装饰模式,8.适配器模式,9.组合模式,10.桥梁模式,11.外观模式,12.享元模式
        三、行为型:13.模板方法模式,14.命令模式,15.责任链模式,16.策略模式,17.迭代器模式,18.中介者模式,19.观察者模式,20.备忘录模式,21.访问者模式,22.状态模式,23.解释器模式

    不可绕过的六大原则:
        一、单一职责原则:一个类应该只有一个引起它变化的原因,即一个类应该只有一个职责。【举例见下文】
        二、里氏替换原则:如果对于一个类型S的对象o1,都有一个类型为S的对象o2,使得以S定义的所有程序P在所有对象o1都能转换成o2时,程序P的行为没有发生变化,那么类型T是类型S的子类。(或者也可以这样说:所有使用基类的地方都能透明的使用其子类对象。)【举例见下文】
        三、依赖倒置原则:高层模块不应该依赖底层模块,两者都应该依赖抽象;抽象不应依赖细节,细节应该依赖抽象。(抽象是指抽象类或者接口;细节是指实现类)【举例见下文】
        四、接口隔离原则:客户端不应该依赖它不需要的借口。(或者这一这样说:类的依赖应该建立在最小的接口上。)【举例见下文】
        五、迪米特法则:一个对象应该对其他对象尽可能的少了解。【举例见下文】
        六、开闭原则:一个软件应该适当的对扩展开放,对修改关闭。意思是,在设计一个模块是应该可以在不被修改的情况下被扩展,即一个模块在不被修改源代码的情况下可以修改其行为。【举例见下文】
        总结:其中开闭原则是总的指导原则,其他(单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则)都是开闭原则的具体形态。

        可能这样只是一些概念型的文字,对我们程序员来说,最直观的还是代码+注释,下面分别举例
        一、单一职责原则

    /**
     * 我们通常都是有这样一个类,这个类的职责就是定义该类型有的属性。
     */
    public class User {
        
        private String name;
        private Integer age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    }
    职责类一
    /**
     * 一般我们还会有这样一个类,它的职责是对User对象做一定的业务逻辑操作
     */
    public class UserServiceImpl {
        public void addUser(User user) {
            //...
        }
    
        public void delUser(String name) {
            //...
        }
    
        public void findUser(String name) {
            //...
        }
    
        public void modifyUser(User user) {
            //...
        }
    }
    职责类二

    随便举个例子说明问题就行了。意思就是我们一般都会在一个类中集中做一种事情,赋予这个类一个职责。所以这可能也是比较混乱的,因为每个人的划分标准可能以相同,所以也别太较真抬杠,所以如果你非要把所有的模型model的添加放在一个service类中,也算符合吧,但小心别人用枪打你。一般我们还是需要和团队形成一样的形式。我们身子弱,为了安全起见。
        二、里氏替换原则

    public class Main {
    
        public static void main(String[] args) {
            Alimal alimal_1 = new Dog();
            Alimal alimal_2 = new Cat();
    
            alimal_1.call();
            alimal_2.call();
        }
    
    }
    
    abstract class Alimal {
        abstract void call();
    }
    
    class Dog extends Alimal {
    
        @Override
        public void call() {
            System.out.println("汪汪汪。。。");
        }
    }
    
    class Cat extends Alimal {
    
        @Override
        public void call() {
            System.out.println("喵喵喵。。。");
        }
    }
    View Code

    其实本来这里的四个类,应该分别在四个文件中,但是为了方便看代码我将它们放在了一起,你会发现,这就是多态里面的性质,什么时候是向上造型,什么时候是向下造型。但这里的里氏替换原则很简单一点,就是凡是父类对象能出现的地方,用子类都可以替换。你会发现里氏替换的第一个定义其实是定义了什么是子类。
        三、依赖倒置原则

    public interface Car {
        void move();
    }
    
    class A implements Car{
    
        @Override
        public void move() {
            System.out.println("开着A车去兜风。。。");
        }
    }
    
    class B implements Car{
    
        @Override
        public void move() {
            System.out.println("开着B车去兜风。。。");
        }
    }
    第一部分
    public interface Drive {
         void drive(Car car);
    }
    
    class SpecialityDrive implements Drive{
    
        @Override
        public void drive(Car car) {
            System.out.println("我是专业的司机");
            car.move();
    
        }
    }
    
    class AmateurDrive implements Drive{
    
        @Override
        public void drive(Car car) {
            System.out.println("我是业余的司机");
            car.move();
        }
    }
    第二部分

    本来还有第三部分,我不想写了,猜也猜到三部分是调用了。重点不在调用而在第二部分,熟悉概念的应该看出来了,都是使用的接口,高层模块不应该依赖底层模块,而是都应该依赖抽象。虽然这里面也体现了一些设计模式,但后面会详细说明,这里不是重点,故略过。
        四、接口隔离原则

    这部分不写代码里吧,感觉如果我把代码写在一起反而不好说明,而且这个应该用文字更好说明。一般一个系统平台都至少有两部分(用户使用的部分:门户,管理人员使用的部分:后台管理),肯定存在一些对象模型,门户的权限不足,比如说商品,门户肯定不允许修改商品的,他们只有显示的,所以我门在定义商品操作接口的时候需要分开定义,虽然看上去是同一个,但这样能避免我们去实现没必要的方法。同时也为了代码更安全。
        五、迪米特法则

    public class tets {
        public static void main(String[] args) {
            Someone one  = new Someone();
            one.call(new Friend());
        }
    }
    
    class Someone{
        public void call(Friend friend){
            friend.forward();
        }
    }
    
    class Friend {
    
        private Stranger stranger = new Stranger();
        public void forward(){
            stranger.strangerMothed();
        }
        public void friendMothed(){
            System.out.println("这里是朋友的方法");
        }
    
    }
    
    class Stranger{
        public void strangerMothed(){
            System.out.println("这里是陌生人的方法");
        }
    }
    View Code

    正常来说肯定也是不在同一个文件的,这一段可能很多人明不能直接的看明白,我整理一下迪米特法则的解释描述:“只跟直接的朋友进行沟通”;“不跟陌生人说话”;“对其他的单位了解的越少越好”。知道这三条解释以后,我们再来理解以上的代码,someone 想要调用一个他不认识的人的方法,他不直接去调用,而是通过friend这样一个中间人去调用,如比说相约一个在餐厅遇到的漂亮女孩,我们不要直接过去,而是通过朋友,或许朋友也不直接认识他,那就再找朋友的朋友,以此类推,就以一个熟人的身份约到了她。类似的做法,我们通常的结构可能是Controller->Service->Mapper,在这个结构中,我们都是将Service对象注入Controller中,将Mapper对象注入Service中,尽可能不要让Controller和Mapper直接接触,因为控制层和操作层中间还有业务层,控制层和操作层是陌生人的关系。
        六、开闭原则

    public interface Book {
    
        String getName();
        BigDecimal getPrice();
    
    }
    
    class NovelBook implements Book{
    
        public NovelBook(String name,BigDecimal price){
            this.name = name;
            this.price = price;
        }
    
        private String name;
        private BigDecimal price;
    
        @Override
        public String getName() {
            return this.name;
        }
    
        @Override
        public BigDecimal getPrice() {
            return price;
        }
    }
    
    class OldNovelBook extends NovelBook{
    
        public OldNovelBook(String name, BigDecimal price) {
            super(name, price);
        }
    
        public BigDecimal getPrice(){
            return super.getPrice().multiply(new BigDecimal("0.7"));
        }
    }
    View Code

    同样的,调用的部分我没有写,但应该已经想到明显,调用的时候统一使用接口Book,但我们传入的时候,可能传入的是NovelBook,也可能传入的是OldNovelBook,旧的小说的价格会打七折,所以我们不需要修改什么代码,只要按照一定的日期区分新旧数据,船舰对象的时候区分出来,价格就自然会打折,这就是开闭原则,在尽可能不修改代码的情况下使用扩展性改变原有的行为。

      总结
    其实这只是个引子,但其实也还算重要,这是一些设计模式主要思想框架。有些我们可能只是不知道名称,但平时就在使用,但不知道名称有一个很尴尬的就是无法和别人交流,或者你觉得什么东西很好,但是你不知道怎么表达。斯坦福大学的一个教授说过一句话,“当一个事物出现时,我们总是先赋予它一个名称,其实并不是一定要给他一个名字,只是为了赋予我们使用它的能力”。

  • 相关阅读:
    Spring中这么重要的AnnotationAwareAspectJAutoProxyCreator类是干嘛的?
    Spring到底应该学哪些内容?
    如何评价《Java 并发编程艺术》这本书?
    在腾讯工作是一种怎样的体验?
    图解 HTTP 连接管理
    42 张图带你撸完 MySQL 优化
    我是如何进入腾讯的?
    《计算机网络 PDF》搞起!
    JSR
    RelationNet:学习目标间关系来增强特征以及去除NMS | CVPR 2018
  • 原文地址:https://www.cnblogs.com/ben-mario/p/10641516.html
Copyright © 2020-2023  润新知