zoukankan      html  css  js  c++  java
  • 设计模式之六大设计原则学习笔记

    六大设计原则学习笔记

    单一职责原则

    应该有且仅有一个原因引起累的变更。
    tips:当有一个类有多个职责可以实现多个接口。

    里氏替换原则

    继承的特点:

    • 代码共享,提高代码的重用性,
    • 提高代码的可扩展性
    • 侵入性(子类必须有父类所以的属性和方法),降低了灵活性
    • 增强了耦合性

    里氏替换原则的定义:

    所有引用基类的地方必须能透明地使用其子类的对象 
    
    • 子类必须完全实现父类的方法
    • 子类可以有自己的个性
    • 覆盖或实现父类的方法时输入参数可以被放大
    • 覆写或实现弗雷德方法时输出结果可以被缩小

    依赖倒置原则

    依赖倒置原则的含义:

    • 高层模块不应该依赖底层模块,二者都应该依赖其抽象
    • 抽象不应该依赖细节
    • 细节应该依赖抽象

    在java中的表现:

    • 模块间的依赖通过抽象发生,实现类之间发生直接的依赖关系,,其依赖关系通过接口或抽象类产生
    • 接口或抽象类不依赖于实现类
    • 实现类依赖接口或抽象类

    例:以人或者司机开汽车为例。

    //司机接口
    public interface IDriver {
    	public void driver(ICar car);
    }
    //司机实现
    public class Driver implements IDriver{
    	@Override
    	public void drive(ICar car) {
    		car.run();
    	}
    }
    //汽车接口
    public interface ICar {
    	public void run();
    }
    //奔驰车实现
    public class Benz implements ICar{
    	@Override
    	public void run() {
    		System.out.println("Benz车正在运行...");
    	}
    }
    //宝马车实现
    public class Bmw implements ICar{
    	@Override
    	public void run() {
    		System.out.println("Bmw车正在运行...");
    	}
    }
    /**
     * 张三开奔驰车
     */
    public class Client1 {
    	public static void main(String[] args) {
    		IDriver ZhangSan = new Driver();
    		ICar benz = new Benz();
    		ZhangSan.drive(benz);
    	}
    }
    /**
     * 张三开宝马车
     */
    public class Client2 {
    	public static void main(String[] args) {
    		IDriver ZhangSan = new Driver();
    		ICar bmw = new Bmw();
    		ZhangSan.drive(bmw);
    	}
    }
    

    从上面的列子我们可以看出,高层模块,如client和driver,不依赖底层模块的,只是依赖接口,如,driver中的car对象只是以ICar声明,通过接口产生;client中也是通过IDriver和ICar来声明对象。

    依赖的三种写法:

    • 构造函数传递依赖对象

        public interface IDriver {
        	public void driver();
        }
        
        public class Driver implements IDriver{
        	private ICar car;
        	//构造函数注入
        	public Driver(ICar _car){
        		this.car = _car
        	}
        	@Override
        	public void driver() {
        		this.car.run();
        	}
        }
      
    • Setter方法传递依赖对象

        public interface IDriver {
        	public void setCar(ICar car);
        	public void driver();
        }
        
        public class Driver implements IDriver{
        	private ICar car;
        	//Setter方法
        	public setCar(ICar _car){
        		this.car = _car
        	}
        	@Override
        	public void driver() {
        		this.car.run();
        	}
        }
      
    • 接口声明依赖对象

        //这段的第一段很长的程序,就是这种情况
        public interface IDriver {
        	public void driver(ICar car);
        }
        public class Driver implements IDriver{
        	@Override
        	public void drive(ICar car) {
        		car.run();
        	}
        }
      

    接口隔离原则

    定义:

    • 客户端不应该依赖它不需要的接口
    • 类间的依赖关系应该建立在最小的接口上

    原则:

    • 接口要尽量小

      这是接口隔离原则的核心定义,不出现臃肿的接口(Fat Interface),但是“小”是有限度的,首先就是不能违反单一职责原则。根据接口隔离原则拆分接口时,首先必须满足单一职责原则。

    • 接口要高内聚

      高内聚就是要提高接口、类、模块的处理能力,减少对外的交互。具体到接口隔离原则就是,要求在接口中尽量少公布public方法,接口是对外的承诺,承诺地越少对系统开发越有利,变更的风险也就越少,同时也有利于降低成本。

    • 定制服务

      定制服务就是单独为一个个体提供优良的服务。

    • 接口设计是有限度的

      接口的设计粒度越小,系统越灵活,这是不争的事实。但是,灵活的同时也带来了结构的复杂化,开发难度增加,可维护性降低,这不是一个项目或产品所期望看到的,所以接口设计一定要注意适度,这个度只能根据经验和常识判断,没有一个固化或可测量的标准。

    迪米特法则LOD(最少知识原则LKP)

    一个对象应该对其他对象有最少的了解
    一个类应该对自己需求耦合或调用的类知道的最少,你(被耦合或调用的类)的内部是多么的复杂都和我没有关系
    低耦合

    开闭原则

    一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

    在设计一个模块时,应当使这个模块可以在不被修改的前提下被扩展,换言之,应当可以在不必修改源代码的情况下改变这个模块的行为;因为所有软件系统中 有一个共同的特性,即它们的需求都会随时间的推移而发生变化,在软件系统面临新的需 求时,满足开-闭原则的软件中,系统已有模块(特别是最重要的抽象层)不能再修改,而 通过扩展已有的模块(特别是最重要的抽象层),可以提供新的行为,以满足需求。

    开-闭原则如果从另一个角度讲述,就是所谓可变性封装原则(Principle of Encapsulation of Variation,略写作EVP),找到系统的可变因素,将之封装起来。 也就是:考虑你的设计中有什么可能发生变化,允许这些变化而不让这些变化 导致重新设计。可变性封装原则意味着:

    一种可变性不应当散落在代码的很多角落,而应当被封装到一个对象中,同一种可变性 的不同表现可以体现在子类中,继承应当被看做是封装变化的方法,而不仅仅看做是从父类派生子类
    一种可变性不应当与另一种可变性混合在一起,所以一个设计模中,类图的继承层次 不会超过两层,不然就意味着将两种可变性混在一起
    

    做到开闭原则不是件容易的事,但也很多规律可循,这些规律也同样以设计原则的身份 出现,它们都是开-闭原则的手段和工具,是附属于开-闭原则的。
    例:模拟书店销售书籍为例

    public interface IBook {
    	public String getName();
    	public int getPrice();
    	public String getAuthor();
    }
    
    public class NovelBook implements IBook {
    	private String name;
    	private int price;
    	private String author;
    	@Override
    	public String getName() {
    		return this.name;
    	}
    	@Override
    	public int getPrice() {
    		return this.price;
    	}
    	@Override
    	public String getAuthor() {
    		return this.author;
    	}
    	public NovelBook (String _name, int _price, String _author){
    		this.name = _name;
    		this.price = _price;
    		this.author = _author;
    	}
    }
    
    public class BookStore {
    	private final static ArrayList<IBook> booklist = new ArrayList<IBook>();
    	static{
    		booklist.add(new NovelBook("天龙八部",32,"金庸"));
    		booklist.add(new NovelBook("巴黎圣母院",40,"雨果"));
    		booklist.add(new NovelBook("悲惨世界",43,"雨果"));
    	}
    	public static void main(String[] args) {
    		System.out.println("------ 模拟书店卖出去的书记录如下 ------");
    		for (IBook book:booklist) {
    			System.out.print("--- 卖出书:"+book.getName());
    			System.out.print("---价格:"+book.getPrice());
    			System.out.println("---作者:"+book.getAuthor());
    		}
    	}
    }
    

    然而,现在由于需要而需将书打折出售,原价大于40元的9折,原价小于40的八折。

    有三种方法解决这类问题

    • 修改接口
    • 修改实现类(有时候不适用)
    • 通过扩展实现变化

    对于上面的例子,解决办法如下:

    • 对于第一种,可以修改iBook接口,添加getOffPrice()方法
    • 对于第二种,可以修改NovelBook中的getPrice方法
    • 对于第三种,,添加一个OffNovelBook实现iBook接口
  • 相关阅读:
    个人冲刺二(7)
    个人冲刺二(6)
    个人冲刺二(5)
    个人冲刺二(4)
    对称二叉树 · symmetric binary tree
    108 Convert Sorted Array to Binary Search Tree数组变成高度平衡的二叉树
    530.Minimum Absolute Difference in BST 二叉搜索树中的最小差的绝对值
    pp 集成工程师 mism师兄问一问
    17. Merge Two Binary Trees 融合二叉树
    270. Closest Binary Search Tree Value 二叉搜索树中,距离目标值最近的节点
  • 原文地址:https://www.cnblogs.com/byonecry/p/4153764.html
Copyright © 2011-2022 走看看