- 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
- 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
- 行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
- 开闭原则(Open Close Principle)
- 对扩展开放,对修改关闭。
- 里氏代换原则(Liskov Substitution Principle)
- 只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
- 依赖倒转原则(Dependence Inversion Principle)
- 这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。
- 接口隔离原则(Interface Segregation Principle)
- 使用多个隔离的借口来降低耦合度。
- 迪米特法则(最少知道原则)(Demeter Principle)
- 一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
- 合成复用原则(Composite Reuse Principle)
- 原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改。
简单工厂模式(Simple Method)
使用工厂模式的原因:
工厂模式是为了解耦:把对象的创建和使用的过程分开。就是Class A 想调用Class B,那么只是调用B的方法,而至于B的实例化,就交给工厂类。
工厂模式可以降低代码重复。如果创建B过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。可以把这些创建对象B的代码放到工厂里统一管理。既减少了重复代码,也方便以后对B的维护。
工厂模式可以减少错误,因为工厂管理了对象的创建逻辑,使用者不需要知道具体的创建过程,只管使用即可,减少了使用者因为创建逻辑导致的错误。
就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图:
举例如下:(我们举一个发送邮件和短信的例子)
//首先,创建二者的共同接口 public interface Sender { public void Send(); } -------------------------------------------------- //其次,创建实现类 public class MailSender implements Sender { @Override public void Send() { System.out.println("this is mailsender!"); } } public class SmsSender implements Sender { @Override public void Send() { System.out.println("this is sms sender!"); } } -------------------------------------------------- //最后,建工厂类 public class SendFactory { public Sender produce(String type) { if ("mail".equals(type)) { return new MailSender(); } else if ("sms".equals(type)) { return new SmsSender(); } else { System.out.println("请输入正确的类型!"); return null; } } } -------------------------------------------------- //我们来测试下 public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produce("sms"); sender.Send(); } } //输出:this is sms sender!
抽象工厂模式(Abstract Factory)
- 用来生成同一等级结构中的任意产品,,对于增加新的产品,需要修改已有代码
//创建面条基类 public abstract class INoodles { /** * @Description: ${描述面条} * @param ${tags} * @return ${return_type} * @throws * @author RestartYang * @date 2018/5/8 10:20 */ public abstract void desc(); } //创建兰州拉面 public class LzNoodles extends INoodles { @Override public void desc() { System.out.println("兰州拉面"); } } //创建新疆拉面 public class XjNoodles extends INoodles { @Override public void desc() { System.out.println("新疆拉面"); } } //创建咸菜基类 public interface XianCai { public void addTaste(); } //创建老干妈咸菜 public class LGMXianCai implements XianCai { @Override public void addTaste() { System.out.println("老干妈咸菜"); } } //创建工厂抽象接口 public interface Factory { INoodles createLZNoodles(); XianCai createLGMXianCai(); } //创建工厂实现类 public class IFactory implements Factory { @Override public INoodles createLZNoodles() { return new LzNoodles(); } @Override public XianCai createLGMXianCai() { return new LGMXianCai(); } } //使用抽象工厂 public class AbstractFactoryDemo { public static void main(String[] args) { Factory factory = new IFactory(); INoodles lzNoodles = factory.createLZNoodles(); lzNoodles.desc(); XianCai xianCai = factory.createLGMXianCai(); xianCai.addTaste(); } }
工厂方法模式(Factory Method)
- 工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
- 请看例子:
public interface Sender { public void Send(); } -------------------------------------------------- //两个实现类 public class MailSender implements Sender { @Override public void Send() { System.out.println("this is mailsender!"); } } public class SmsSender implements Sender { @Override public void Send() { System.out.println("this is sms sender!"); } } -------------------------------------------------- //再提供一个接口: public interface Provider { public Sender produce(); } -------------------------------------------------- //两个工厂类 public class SendMailFactory implements Provider { @Override public Sender produce(){ return new MailSender(); } } public class SendSmsFactory implements Provider{ @Override public Sender produce() { return new SmsSender(); } } -------------------------------------------------- //测试类 public class Test { public static void main(String[] args) { Provider provider = new SendMailFactory(); Sender sender = provider.produce(); sender.Send(); } }
其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好。
单例模式(Singleton)
- 单例模式是设计模式中最常见也最简单的一种设计模式,保证了在程序中只有一个实例存在并且能全局的访问到。
- 优点:
- 在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
- 缺点:
- 没有抽象层,因此扩展很难。
- 职责过重,在一定程序上违背了单一职责
- 常用的使用方式:
- 饿汉式【在加载那个类的时候,对象的创建工作就已经完成了】
package org.westos_03; //学生类 class Student { private Student() { } //成员位置创建该类的实例 //静态方法只能访问静态变量,所以这个Student方法要加上static,下边的方法才能调用这个对象s //加入私有修饰,防止定义对象之前将Student s=null private static Student s = new Student() ; //静态的类变量 //提供一个公共的成员方法 public static Student getStudent() { return s ; } } public class StudentDemo { public static void main(String[] args) { Student s1 = Student.getStudent() ; Student s2 = Student.getStudent(); System.out.println(s1==s2);//true System.out.println(s1); //org.westos_03.Student@70dea4e System.out.println(s2); //org.westos_03.Student@70dea4e } }
- 懒汉式【需要的时候才进行创建工作】
package org.westos_04; //老师类 class Teacher { //无参构造私有化 private Teacher() { } //在成员位置声明变量 //私有化,并且使用静态修饰 private static Teacher t = null ; //因为懒汉式是非线程安全的,所以需要使用同步方法(synchronized)解决; //静态的同步方法 (锁对象: 类名.class) public synchronized static Teacher getTeacher() { if(t==null) { t = new Teacher() ; } return t ; } } public class TeacherDemo { public static void main(String[] args) { //调用getTeacher()功能 Teacher t1 = Teacher.getTeacher() ; Teacher t2 = Teacher.getTeacher() ; System.out.println(t1==t2); System.out.println(t1); //org.westos_04.Teacher@70dea4e System.out.println(t2); //org.westos_04.Teacher@70dea4e } }
建造者模式(Builder)
- 在了解之前,先假设有一个问题,我们需要创建一个学生对象,属性有name、number、class、sex、age、school等属性,如果每一个属性都可以为空,也就是说我们可以只用一个name,也可以用一个school、name,或者一个class、number,或者其他任意的赋值来创建一个学生对象,这时该怎么构造?
public class Builder { static class Student{ String name = null ; int number = -1 ; String sex = null ; int age = -1 ; String school = null ; //构建器,利用构建器作为参数来构建Student对象 static class StudentBuilder{ String name = null ; int number = -1 ; String sex = null ; int age = -1 ; String school = null ; public StudentBuilder setName(String name) { this.name = name; return this ; } public StudentBuilder setNumber(int number) { this.number = number; return this ; } public StudentBuilder setSex(String sex) { this.sex = sex; return this ; } public StudentBuilder setAge(int age) { this.age = age; return this ; } public StudentBuilder setSchool(String school) { this.school = school; return this ; } public Student build() { return new Student(this); } } public Student(StudentBuilder builder){ this.age = builder.age; this.name = builder.name; this.number = builder.number; this.school = builder.school ; this.sex = builder.sex ; } } public static void main( String[] args ){ Student a = new Student.StudentBuilder().setAge(13).setName("LiHua").build(); Student b = new Student.StudentBuilder().setSchool("sc").setSex("Male").setName("ZhangSan").build(); } }
原型模式(Protype)
- 原型模式就是讲一个对象作为原型,使用clone()方法来创建新的实例。
public class Prototype implements Cloneable{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override protected Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); }finally { return null; } } public static void main ( String[] args){ Prototype pro = new Prototype(); Prototype pro1 = (Prototype)pro.clone(); } }
- 此处使用的是浅拷贝,关于深浅拷贝,大家可以另行查找相关资料
适配器模式(Adapter)
- 适配器模式的意图是将一个已存在的 类 / 接口 进行复用,将其 转换 / 具体化 成客户希望的另外的一个类/接口。
package exercise; //定义一个手机类 class Mobile{ public static final int V=220; //定义接入手机的电压为220伏 //需要进入电源适配器 否则手机就炸了 private VoltageAdapter voltageAdapter; public Mobile(VoltageAdapter voltageAdapter) { this.voltageAdapter = voltageAdapter; } //手机充电 public void charge(){ //调用适配器方法以替换手机的充电方法 voltageAdapter.StepDownCharge(); } } //电源适配器 --降压 class VoltageAdapter{ //降压充电 --额定充电 public void StepDownCharge(){ System.out.println("准备充电..."); System.out.println("原始电压:" + Mobile.V + "V"); System.out.println("经过变压器转换之后的电压:" + (Mobile.V - 200) + "V"); System.out.println("快速充电中..."); } } public class Test3 { public static void main(String args[]){ //创建一个电源适配器 VoltageAdapter voltageAdapter = new VoltageAdapter(); //创建一个手机 Mobile mobile = new Mobile(voltageAdapter); //充电 mobile.charge(); } }
装饰模式(Decorator)
- 动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类更为灵活。该模式以对客 户端透明的方式扩展对象的功能。
- 例如:
//Component public interface Person { void eat(); } //ConcreteComponent public class Man implements Person { public void eat() { System.out.println("男人在吃"); } } //Decorator public abstract class Decorator implements Person { protected Person person; public void setPerson(Person person) { this.person = person; } public void eat() { person.eat(); } } //ConcreteDectrator public class ManDecoratorA extends Decorator { public void eat() { super.eat(); reEat(); System.out.println("ManDecoratorA类"); } public void reEat() { System.out.println("再吃一顿饭"); } } public class ManDecoratorB extends Decorator { public void eat() { super.eat(); System.out.println("==============="); System.out.println("ManDecoratorB类"); } } //Test public class Test { public static void main(String[] args) { Man man = new Man(); ManDecoratorA md1 = new ManDecoratorA(); ManDecoratorB md2 = new ManDecoratorB(); md1.setPerson(man); md2.setPerson(md1); md2.eat(); } }
代理模式(Proxy)
- 所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
- 代理模式的UML图:
- 客户端通过代理类访问,代理类实现具体的实现细节,客户只需要使用代理类即可实现操作。
- 这种模式可以对旧功能进行代理,用一个代理类调用原有的方法,且对产生的结果进行控制。
//Subject接口的实现 interface Subject { void visit(); } //实现了Subject接口的两个类: class RealSubject implements Subject { private String name = "byhieg"; @Override public void visit() { System.out.println(name); } } class ProxySubject implements Subject{ private Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } @Override public void visit() { subject.visit(); } } //具体的调用如下 public class Client { public static void main(String[] args) { ProxySubject subject = new ProxySubject(new RealSubject()); subject.visit(); } }
外观模式(Facade)
桥接模式(Bridge)
- 桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化。桥接的用意是:将抽象化与实现化解耦,使得二者可以独立变化
//先定义接口 public interface Sourceable { public void method(); } //分别定义两个实现类 public class SourceSub1 implements Sourceable { @Override public void method() { System.out.println("this is the first sub!"); } } public class SourceSub2 implements Sourceable { @Override public void method() { System.out.println("this is the second sub!"); } } //定义一个桥,持有Sourceable的一个实例 public abstract class Bridge { private Sourceable source; public void method(){ source.method(); } public Sourceable getSource() { return source; } public void setSource(Sourceable source) { this.source = source; } } public class MyBridge extends Bridge { public void method(){ getSource().method(); } } //测试类 public class BridgeTest { public static void main(String[] args) { Bridge bridge = new MyBridge(); /*调用第一个对象*/ Sourceable source1 = new SourceSub1(); bridge.setSource(source1); bridge.method(); /*调用第二个对象*/ Sourceable source2 = new SourceSub2(); bridge.setSource(source2); bridge.method(); } } //输出: //this is the first sub! //this is the second sub!
组合模式(Composite)
享元模式(Flyweight)
- 享元模式:“享”就是分享之意,指一物被众人共享,而这也正是该模式的终旨所在。
- 享元模式有点类似于单例模式,都是只生成一个对象来被共享使用。这里有个问题,那就是对共享对象的修改,为了避免出现这种情况,我们将这些对象的公共部分,或者说是不变化的部分抽取出来形成一个对象。这个对象就可以避免到修改的问题。
- 享元的目的是为了减少不会要额内存消耗,将多个对同一对象的访问集中起来,不必为每个访问者创建一个单独的对象,以此来降低内存的消耗。
命令模式(Order)