几种必须掌握的设计模式
23种设计模式作用和关系(笔试选择题)
设计模式UML图(笔试常考)
https://blog.csdn.net/bwwlpnn/article/details/7421628
设计模式的六大原则
-
开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。 -
里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科 -
依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。 -
接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。 -
迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 -
合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
单例设计模式
实现单例模式需要三步:
- 将构造函数私有化
- 在类的内部创建实例
- 提供获取唯一实例的方法
单例模式分为饿汉式和简单懒汉式
饿汉式
//饿汉式(直接创建出一个对象,并返回)
public class Singleton{
//私有化构造函数
private Singleton(){
}
//创建对象
private static Singleton ins=new singleton();
//返回唯一对象
public static Singleton getInstance(){
return ins;
}
}
缺点:一上来就创建对象,如果没有用过会造成内存浪费
简单懒汉式
//懒汉式
public class Singleton{
//私有化构造函数
private Singleton(){}
//先不创建对象,等用到的时候再创建
private static volatile Singleton ins=null; //避免重排序,volatile有内存屏障的功能
//调用到这个方法了,证明是要被用到的了
public static Singleton getInstance(){
if(ins==null){ //这个判断主要为了提高性能
synchronized(Singleton.class){ //使用synchronized将锁的范围缩小,提高性能
if(ins==null){ //再判断一次是否为null(主要的判断)
ins=new Singleton();
}
}
}
return ins;
}
}
工厂设计模式
使用工厂模式好处:可以降低耦合,即想要修改某个具体的实现类,只需要修改工厂,对客户端(调用方)而言是完全不用修改的。
开闭原则:对扩展开放,对修改封闭。
静态工厂增加需要是修改源代码,对修改不封闭,所以不符合开闭原则。
工厂模式分成三种:
简单/静态工厂模式 (最常用的,只有一个具体的工厂来创建对象,代码量少)
不用创建接口,创建实例的方法都是static的
public class AnimalFactory {
public static Dog createDog() {
return new Dog();
}
public static Cat createCat() {
return new Cat();
}
// 外界想要猫要狗,这里创建就好了
public static Animal createAnimal(String type) { //静态方法:方便被直接调用
if ("dog".equals(type)) { //这个方法把上面的猫狗方法都包含了,所以称为工厂
return new Dog();
} else if ("cat".equals(type)) {
return new Cat();
} else {
return null;
}
}
}
想要获得具体的对象时:不需要创建实例对象,用到的时候直接调用工厂静态方法就行了
// 拿到狗
Animal A = AnimalFactory.createAnimal("dog"); //直接调用工厂方法即可
A.eat();
// 拿到猫
Animal C = AnimalFactory.createAnimal("cat");
C.eat();
工厂方法模式
抽象工厂模式
https://segmentfault.com/a/1190000014949595#articleHeader3 这篇文章写的还不错
策略模式
主要包括三个部分:
- 策略的接口
- 具体的实现
- Context上下文对象:起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
策略模式的思想:出行可以选择骑车和驾车两种方式,但选择不是直接调用自行车或汽车,而是要通过人来进行,这里的人就是上下文对象(使用人,更符合面向对象的特性,屏蔽了直接对具体实现的访问)
若想要添加一种出行方式,直接添加一个实现类,最终让人来调用即可
具体实现:
出行交通工具接口
public interface Vehicle{
void goOut();
}
自行车实现类:
public class Bike implements Vehicle{
public void goOut(){
System.out.println("选自行车出行");
}
}
汽车实现类:
public class Car implements Vehicle{
public void goOut(){
System.out.println("选汽车出行");
}
}
火车实现类:
public class Train implements Vehicle{
public void goOut(){
System.out.println("选火车出行");
}
}
定义人这个类:
自行车实现类:
public class Person{
Vehicle myVehicle; //定义Vehicle变量
//构造函数(注意参数)
public Person(Vehicle myVehicle){
this.myVehicle=myVehicle;
}
//具体执行的方法
public void exec(){
myVehicle.goOut();
}
}
等到具体的某一天,就可以创建几个人对象来选择出行的交通工具
public class Main{
public static void main(String[] args){
Person tom=new Person(new Bike());
tom.exec(); //tom骑车出行
Person jack=new Person(new Car());
jack.exec(); //jack驾车出行
}
}
装饰模式
装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。
装饰模式动态地给一个对象添加一些额外的职责,就增加功能来说,它比生成子类更灵活。也可以这样说,装饰模式把复杂类中的核心职责和装饰功能区分开了,这样既简化了复杂类,有去除了相关类中重复的装饰逻辑。 装饰模式没有通过继承原有类来扩展功能,但却达到了一样的目的,而且比继承更加灵活,所以可以说装饰模式是继承关系的一种替代方案。
适配器模式 Adapter
适配器模式是将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
两个成熟的类需要通信,但是接口不同,由于开闭原则,我们不能去修改这两个类的接口,所以就需要一个适配器来完成衔接过程。
桥接模式 Bridge
桥接模式将抽象部分与它的实现部分分离,是它们都可以独立地变化。它很好的支持了开闭原则和组合锯和复用原则。实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这些多角度分离出来让他们独立变化,减少他们之间的耦合。
观察者模式
定义对象间的一种一对多的关系,当一个对象的状态发生改变时,所依赖于它的对象都得到通知并被自动更新。
如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变,应该使用观察者模式