六、设计模式

1. 单例模式

核心作用:保证一个类只有一个对象,提供一个方法访问这个对象。例如:回收站和任务管理器Spring的Bean就是。
优点:减少系统性能的开销。
实现方式:饿汉式,懒汉式 其他:双重检测锁,静态内部类,枚举单例

  1. 饿汉式
    私有构造器,提供一个私有属性(创建一个对象),提供一个取对象方法。
public class Demo1 {

    //饿汉式,类初始化时立刻加载,线程安全调用效率高
    private static Demo1 demo1 = new Demo1();

    private Demo1(){
    }

    public static Demo1 getDemo1(){
        return demo1;
    }
}
  1. 懒汉式
public class Demo1 {

    //懒汉式,需要加载同步块,资源利用率高,调用效率低
    private static Demo1 demo1;

    private Demo1(){
    }

    public static synchronized Demo1 getDemo1(){
        if (demo1 == null)
            demo1 = new Demo1();
        return demo1;
    }
}

2. 工厂模式

核心本质是实例化对象,用工厂方法代替new操作。将选择实现类,创建对象统一管理和控制,从而将调用者和实现类解耦。

  1. OCP(开闭原则):一个软件的实体应该对扩展开放,对修改关闭。
  2. DIP(依赖倒转原则): 要针对接口编程,不要针对实现编程。
  3. LoD(迪米特法则): 只与你的直接朋友通信,避免和陌生人通信。
  4. 简单工厂模式:(简单且常用)
//在没有工厂模式的情况下
public class Client01 {
    public static void main(String[] args) {
        Car c1 = new Audi();
        Car c2 = new Byd();
        c1.run();
        c2.run();
    }
}

public class CarFactory {
    public Car createCar(String type){
        if ("audi".equals(type)){
            return new Audi();
        }else if ("biyadi".equals(type)){
            return new Byd();
        }else
            return null;
    }
}
//在有简单工厂模式的情况下
public class Client01 {
    public static void main(String[] args) {
        Car c1 = CarFactory.createCar("audi");
        Car c2 = CarFactory.createCar("biyadi");
        c1.run();
        c2.run();
    }
}


这个时候client只需要知道两个东西就行了。
但是如果想增加新的接口一定要修改已有的方法代码,这是违反开闭原则的。

  1. 工厂方法模式
public interface CarFactory {
    Car createCar();
}
public class AudiFactory implements CarFactory{
    @Override
    public Car createCar() {
        return new Audi();
    }
}

public class BydFactory implements CarFactory{
    @Override
    public Car createCar() {
        return new Byd();
    }
}

//在有简单工厂模式的情况下
public class Client01 {
    public static void main(String[] args) {
        Car c1 = new AudiFactory().createCar();
        Car c2 = new BydFactory().createCar();
        c1.run();
        c2.run();
    }
}

扩展的时候只需要增加新类来扩展,不需要修改代码。

  1. 抽象工厂模式:

package com.example.annotation.bean;

public interface Engine{
    void run();
    void start();
}
class LuxuryEngine implements Engine{
    @Override
    public void run() {
        System.out.println("转的快");
    }

    @Override
    public void start() {
        System.out.println("启动快");
    }
}
class LowEngine implements Engine{
    @Override
    public void run() {
        System.out.println("转的慢");
    }

    @Override
    public void start() {
        System.out.println("启动慢");
    }
}
package com.example.annotation.bean;

public interface Seat {
    void massage();
}

class LuxurySeat implements Seat{

    @Override
    public void massage() {
        System.out.println("可以按摩");
    }
}

class LowSeat implements Seat{

    @Override
    public void massage() {
        System.out.println("不可以按摩");
    }
}
package com.example.annotation.bean;

public interface Tyre {
    void revolve();
}
class LuxuryTyre implements Tyre{
    @Override
    public void revolve() {
        System.out.println("转的快");
    }
}
class LowTyre implements Tyre{
    @Override
    public void revolve() {
        System.out.println("转的慢");
    }
}
package com.example.annotation.bean;

public interface CarFactory {
    Engine createEngine();
    Seat createSeat();
    Tyre createTyre();
}

class LuxuryCarFactory implements CarFactory{

    @Override
    public Engine createEngine() {
        return new LuxuryEngine();
    }

    @Override
    public Seat createSeat() {
        return new LuxurySeat();
    }

    @Override
    public Tyre createTyre() {
        return new LuxuryTyre();
    }
}

class LowCarFactory implements CarFactory{

    @Override
    public Engine createEngine() {
        return new LowEngine();
    }

    @Override
    public Seat createSeat() {
        return new LowSeat();
    }

    @Override
    public Tyre createTyre() {
        return new LowTyre();
    }
}
package com.example.annotation.bean;

//在有简单工厂模式的情况下
public class Client01 {
    public static void main(String[] args) {
        CarFactory factory = new LuxuryCarFactory();
        Engine e = factory.createEngine();
        e.run();
        e.start();
    }
}

3. 建造者模式

我们要建造一个复杂的产品,装配这些子组件有一个步骤顺序的问题。
本质上分离了对象子组件的单独构造(由Builder负责)和装配(由Director负责),从而可以构建出复杂的对象。适用于某个对象的构建过程复杂的情况下使用。

//宇宙飞船
public class AirShip {
    private OrbitalModule orbitalModule; //轨道舱
    private Engine engine; //发动机
    private EscapeTower escapeTower; //逃离塔

    public void launch(){
        System.out.println("发射");
    }

    public OrbitalModule getOrbitalModule() {
        return orbitalModule;
    }

    public void setOrbitalModule(OrbitalModule orbitalModule) {
        this.orbitalModule = orbitalModule;
    }

    public Engine getEngine() {
        return engine;
    }

    public void setEngine(Engine engine) {
        this.engine = engine;
    }

    public EscapeTower getEscapeTower() {
        return escapeTower;
    }

    public void setEscapeTower(EscapeTower escapeTower) {
        this.escapeTower = escapeTower;
    }
}

class OrbitalModule {
    private String name;
    public OrbitalModule(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class Engine{
    private String name;
    public Engine(String name){
        this.name= name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class EscapeTower{
    private String name;
    public EscapeTower(String name){
        this.name= name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public interface AirShipBuilder {
    OrbitalModule builderOrbitalModule();
    Engine builderEngine();
    EscapeTower builderEscapeTower();

}

public interface AirShipDirector {
    //组装飞船对象
    AirShip directAirShip();
}

public class NeuAirshipDirector implements AirShipDirector{
    private AirShipBuilder builder;

    public NeuAirshipDirector(AirShipBuilder builder) {
        this.builder = builder;
    }

    @Override
    public AirShip directAirShip() {
        OrbitalModule o = builder.builderOrbitalModule();
        Engine e = builder.builderEngine();
        EscapeTower et = builder.builderEscapeTower();
        //组装
        AirShip ship = new AirShip();
        ship.setOrbitalModule(o);
        ship.setEngine(e);
        ship.setEscapeTower(et);
        return ship;
    }
}
public class NeuAirShipBuilder implements AirShipBuilder{

    @Override
    public OrbitalModule builderOrbitalModule() {
        System.out.println("构建轨道舱");
        return new OrbitalModule("轨道舱");
    }

    @Override
    public Engine builderEngine() {
        System.out.println("构建发动机");
        return new Engine("发动机");
    }

    @Override
    public EscapeTower builderEscapeTower() {
        System.out.println("构造逃逸塔");
        return new EscapeTower("逃逸塔");
    }
}
public class Client {
    public static void main(String[] args) {
        AirShipDirector director = new NeuAirshipDirector(new NeuAirShipBuilder());
        AirShip ship = director.directAirShip();
        System.out.println(ship.getEngine().getName());
        ship.launch();
    }
}

4. 原型模式 prototype

新建对象(new)很耗时,以某个对象为原型复制出新的对象效率更高。
实现方法:Cloneable接口和clone方法

public class Sheep implements Cloneable{
    private String sname;
    private Date birthday;

    public Sheep(String sname, Date date) {
        this.sname = sname;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException{
        Object obj = super.clone(); //直接调用Object的克隆方法
        return obj;
    }
}

//浅克隆
public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep s1 = new Sheep("dkm",new Date());
        System.out.println(s1); //com.example.annotation.sjms.prototype.Sheep@5caf905d
        Sheep s2 = (Sheep) s1.clone();
        System.out.println(s2); //com.example.annotation.sjms.prototype.Sheep@27716f4
        System.out.println(s1.getSname()); //dkm
        System.out.println(s2.getSname()); //dkm
        s2.setSname("xzq");
        System.out.println(s2.getSname()); //xzq
    }
}

两者指向的同一个date对象,当一个变了另一个也会变。这是因为只克隆了地址。

@Override
    protected Object clone() throws CloneNotSupportedException{
        Object obj = super.clone(); //直接调用Object的克隆方法
        //添加如下代码实现深复制
        Sheep s = (Sheep) obj;
        s.birthday = (Date) this.birthday.clone();
        return obj;
    }

修改了之后引用的类就不会一样了。

5. 适配器模式(adapter)

将一个类的接口转换成客户希望的另外一个接口,Adapter使得原本由于接口不兼容而不能一起工作的类可以在一起工作。
包括:需要适配的类(adaptee),目标接口(Target),适配器(Adapter)

//相当于键盘
public class Adpatee {
    public void request(){
        System.out.println("可以完成客户请求的功能");
    }
}

//适配器本身(类)
public class Adapter extends Adpatee implements Target {
    @Override
    public void handleReq() {
        super.request();
    }
}
public interface Target {
    void handleReq();
}
//相当于笔记本,只有usb接口
public class Client {
    public void test1(Target t){
        t.handleReq();
    }

    public static void main(String[] args) {
        Client c = new Client();
        Adpatee a = new Adpatee();
        Target t = new Adapter();
        c.test1(t); //可以完成客户请求的功能
    }
}

这是类适配方式,但是类是单继承的所以不够灵活

//适配器使用组合的方式跟被试陪对象整合
public class Adapter2 extends Adpatee implements Target {
    private Adpatee adpatee;
    @Override
    public void handleReq() {
        adpatee.request();
    }

    public Adapter2(Adpatee adpatee) {
        this.adpatee = adpatee;
    }
}
//相当于笔记本,只有usb接口
public class Client {
    public void test1(Target t){
        t.handleReq();
    }

    public static void main(String[] args) {
        Client c = new Client();
        Adpatee a = new Adpatee();
        Target t = new Adapter2(a);
        c.test1(t); //可以完成客户请求的功能
    }
}

6. 代理模式(Proxy)

通过代理控制对对象的访问。是AOP(面向切面编程)的核心实现机制。
真实角色:明星(周杰伦)
代理角色:经纪人
抽象角色:定义代理角色和真实角色的公共对外方法
将统一的流程控制放在代理角色中处理。

  1. 静态代理(静态定义代理类)
//抽象角色
public interface Star {
    //面谈
    void confer();
    //签合同
    void signContract();
    void bookTicket();
    void sing();
    //收钱
    void collectMoney();
}
//真实类
public class RealStar implements Star{
    @Override
    public void confer() {
        System.out.println("真实角色");
    }

    @Override
    public void signContract() {
        System.out.println("真实角色");
    }

    @Override
    public void bookTicket() {
        System.out.println("真实角色");
    }

    @Override
    public void sing() {
        System.out.println("真实角色唱歌");
    }

    @Override
    public void collectMoney() {
        System.out.println("真实角色");
    }
}
//代理类
public class ProxyStar implements Star{
    private Star star;

    public ProxyStar(Star star) {
        this.star = star;
    }

    @Override
    public void confer() {
        System.out.println("代理角色");
    }

    @Override
    public void signContract() {
        System.out.println("代理角色");
    }

    @Override
    public void bookTicket() {
        System.out.println("代理角色");
    }

    @Override
    public void sing() {
        star.sing();
    }

    @Override
    public void collectMoney() {
        System.out.println("代理角色");
    }
}

public class Client {
    public static void main(String[] args) {
        Star real = new RealStar();
        Star proxy = new ProxyStar(real);
        proxy.confer(); //代理角色
        proxy.signContract(); //代理角色
        proxy.sing(); //真实角色唱歌
        proxy.collectMoney(); //代理角色
    }
}

  1. 动态代理(dynamic proxy)动态生成代理类
    代理类交给工具生成。
    自带的:java.lang.reflect.Proxy(动态生成代理类和对象),java.lang.reflect.InvocationHandler(处理器接口:可以通过invoke方法实现对真实角色的访问,每次通过Proxy生成代理类对象时都要指定对应的处理器对象)
//抽象角色
public interface Star {
    //面谈
    void confer();
    //签合同
    void signContract();
    void bookTicket();
    void sing();
    //收钱
    void collectMoney();
}
//真实类
public class RealStar implements Star {
    @Override
    public void confer() {
        System.out.println("真实角色");
    }

    @Override
    public void signContract() {
        System.out.println("真实角色");
    }

    @Override
    public void bookTicket() {
        System.out.println("真实角色");
    }

    @Override
    public void sing() {
        System.out.println("真实角色唱歌");
    }

    @Override
    public void collectMoney() {
        System.out.println("真实角色");
    }
}
public class StarHandler implements InvocationHandler {
    Star realStar;

    public StarHandler(Star realStar) {
        this.realStar = realStar;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = null;
        System.out.println("面谈,签合同,等等等");
        if (method.getName().equals("sing")){
            object = method.invoke(realStar,args);
        }
        System.out.println("结束后收尾款等等");
        return object;
    }
}
public class Client {
    public static void main(String[] args) {
        Star realStar = new RealStar();
        StarHandler handler = new StarHandler(realStar);
        Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class},handler);
        proxy.sing();
        //面谈,签合同,等等等
        //真实角色唱歌
        //结束后收尾款等等
    }
}
  1. 动态代理内存调用过程

7. 桥接模式

多层继承结构。

public interface Computer {
    void sale();
}

class Desktop implements Computer{

    @Override
    public void sale() {
        System.out.println("销售台式机");
    }
}

class Laptop implements Computer{

    @Override
    public void sale() {
        System.out.println("销售笔记本");
    }
}

class LenovoDesktop extends Desktop{
    @Override
    public void sale(){
        System.out.println("销售联想台式机");
    }
}

class LenovoLaptop extends Laptop{
    @Override
    public void sale(){
        System.out.println("销售联想笔记本");
    }
}

class SzDesktop extends Desktop{
    @Override
    public void sale(){
        System.out.println("销售神州台式机");
    }
}

class SzLaptop extends Laptop{
    @Override
    public void sale(){
        System.out.println("销售神州笔记本");
    }
}

未使用桥接模式

增加子类特别繁琐,可扩展性有问题。增加新的品牌或者新的电脑类型都很繁琐。这里每个类都承载了两个职责(类型和品牌)违反了单一职责的原则。
桥接模式:将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。

//品牌维度
public interface Brand {
    void sale();
}

class Lenovo implements Brand {

    @Override
    public void sale() {
        System.out.println("销售联想电脑");
    }
}

class Dell implements Brand {

    @Override
    public void sale() {
        System.out.println("销售戴尔电脑");
    }
}
//电脑类型维度
public class Computer2 {
    protected Brand brand;
    Computer2(Brand b){
        this.brand = b;
    }
    public void sale(){
        brand.sale();
    }
}

class Desktop2 extends Computer2 {

    public Desktop2(Brand b) {
        super(b);
    }

    @Override
    public void sale(){
        super.sale();
        System.out.println("销售台式机");
    }
}

class Laptop2 extends Computer2 {

    public Laptop2(Brand b) {
        super(b);
    }

    @Override
    public void sale(){
        super.sale();
        System.out.println("销售笔记本");
    }
}
public class Client {
    public static void main(String[] args) {
        //销售联想的笔记本电脑
        Computer2 c = new Laptop2(new Lenovo());
        c.sale();
        //销售联想电脑
        //销售笔记本
    }
}

这样无论是扩展品牌还是电脑类型都可以只修改一个地方。可以用来取代多层继承结构。

8. 组合模式(composite)

经常由于处理树形的结构。分为抽象构建,容器和叶子。

public interface Component {
    void operation();
}

//叶子组件
interface Leaf extends Component {

}

//容器组件
interface Composite extends Component{
    void add(Component c);
    void remove(Component c);
    Component getChile(int index);
}
public interface Component {
    void operation();
}

//叶子组件
interface Leaf extends Component {

}

//容器组件
interface Composite extends Component{
    void add(Component c);
    void remove(Component c);
    Component getChile(int index);
}

//抽象构建
public interface AbstractFile {
    void killVirus(); // 杀毒
}

//叶子组件
class ImageFile implements AbstractFile {
    private String name;

    public ImageFile(String name) {
        this.name = name;
    }

    @Override
    public void killVirus() {
        System.out.println("--图像文件: " +  name);
    }
}

//叶子组件
class TextFile implements AbstractFile {
    private String name;

    public TextFile(String name) {
        this.name = name;
    }

    @Override
    public void killVirus() {
        System.out.println("--文本文件: " +  name);
    }
}

//容器组件
class Folder implements AbstractFile {
    private String name;
    //定义容器用来存储子节点
    private List<AbstractFile> list = new ArrayList<>();

    public Folder(String name) {
        this.name = name;
    }

    public void add(AbstractFile file){
        list.add(file);
    }

    public void remove(AbstractFile file){
        list.remove(file);
    }

    public AbstractFile get(int index){
        return list.get(index);
    }
    @Override
    public void killVirus() {
        System.out.println("---文件夹: " + name );
        for (AbstractFile file : list){
            file.killVirus();
        }
    }
}
public class Client {
    public static void main(String[] args) {
        Folder f1;
        AbstractFile f2,f3;
        f1 = new Folder("我的收藏");
        f2 = new ImageFile("lalala.jpg");
        f3 = new TextFile("hello.txt");
        f1.add(f2);
        f1.add(f3);
        f1.killVirus();
        //---文件夹: 我的收藏
        //--图像文件: lalala.jpg
        //--文本文件: hello.txt
        f2.killVirus();
        //--图像文件: lalala.jpg
        f3.killVirus();
        //--文本文件: hello.txt
    }
}

树状结构往往都要用到组合模式。

更多推荐

【JAVA学习】六、设计模式