常用的设计模式可概括为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("喵喵喵。。。"); } }
其实本来这里的四个类,应该分别在四个文件中,但是为了方便看代码我将它们放在了一起,你会发现,这就是多态里面的性质,什么时候是向上造型,什么时候是向下造型。但这里的里氏替换原则很简单一点,就是凡是父类对象能出现的地方,用子类都可以替换。你会发现里氏替换的第一个定义其实是定义了什么是子类。
三、依赖倒置原则
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("这里是陌生人的方法"); } }
正常来说肯定也是不在同一个文件的,这一段可能很多人明不能直接的看明白,我整理一下迪米特法则的解释描述:“只跟直接的朋友进行沟通”;“不跟陌生人说话”;“对其他的单位了解的越少越好”。知道这三条解释以后,我们再来理解以上的代码,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")); } }
同样的,调用的部分我没有写,但应该已经想到明显,调用的时候统一使用接口Book,但我们传入的时候,可能传入的是NovelBook,也可能传入的是OldNovelBook,旧的小说的价格会打七折,所以我们不需要修改什么代码,只要按照一定的日期区分新旧数据,船舰对象的时候区分出来,价格就自然会打折,这就是开闭原则,在尽可能不修改代码的情况下使用扩展性改变原有的行为。
总结
其实这只是个引子,但其实也还算重要,这是一些设计模式主要思想框架。有些我们可能只是不知道名称,但平时就在使用,但不知道名称有一个很尴尬的就是无法和别人交流,或者你觉得什么东西很好,但是你不知道怎么表达。斯坦福大学的一个教授说过一句话,“当一个事物出现时,我们总是先赋予它一个名称,其实并不是一定要给他一个名字,只是为了赋予我们使用它的能力”。
原文:https://www.cnblogs.com/ben-mario/p/10641516.html