Java设计模式,看这一篇就够了!

前言


在这里插入图片描述

设计模式的目标:提升代码重用性、可读性、可扩展性、可靠性,还能降低系统中类与类之间的耦合度,使程序呈现高内聚低耦合的特性。程序员在开始工作和学习的初期,要优先学习一下设计模式,逐渐应用到工作当中。写出高质量代码。

设计模式的作用,主要有以下4点:

1.代码重用性

相同功能的代码不用多次编写。

2.可读性

设计模式使程序易读,编程规范性,方便其他程序员的阅读和理解。

3.可扩展性

设计模式能使编写的程序具有良好的可扩展性,满足系统设计的开闭原则。比如策略模式,就是将不同的算法封装在子类中,在需要添加新的算法时,只需添加新的子类,实现规定的接口,即可在不改变现有系统源码的情况下加入新的系统行为。

4.可靠性

设计原则


单一职责

对于类来说,一个类应该只负责一项职责。

依赖倒转

类的具体形式交由使用者来管理

接口隔离

接口拆分最简,类去实现

里氏替换

减少类的继承关系,可以抽象出基类去继承

开闭原则

对修改关闭,对扩展开放,扩展时候尽量不动原来的代码

迪米特法则

减少代码的耦合

合成复用原则

减少类的继承,找出类中复用的东西抽取出来使用

常用 设计模式

单例模式

1.饿汉式(静态常量)

因为是常量(不会变化)且类加载时候实例化,所以没有线程同步问题
缺点:不能懒加载,会可能造成内存浪费

 public class Singleton1 {
        
    //构造器私有化,外部不能new
    private Singleton1(){ }

    //本类内部创建对象实例
    private final static Singleton1 instance = new Singleton1();

    /*提供一个公有的静态方法,返回实例对象*/
    public final static Singleton1 getInstance(){
        return instance;
    }
    
}

2.饿汉式(静态代码块)

 public class Singleton1 {
    static{
        instance = new Singleton1();
    }
        
    private Singleton1(){ }

    private static Singleton1 instance;

    public final static Singleton1 getInstance(){
        return instance;
    }
}

3.懒汉式(线程不安全)

解决了懒加载问题
缺点:有线程安全问题

public class Singleton3 {

    private static Singleton3 instance;

    private Singleton3(){
    }

    public static Singleton3 getInstance(){
        /*使用时才创建*/
        if(instance == null){
            instance = new Singleton3();
        }
        return instance;
    }
}

4.懒汉式(线程安全,加同步锁)

解决了线程安全问题
缺点:效率低

public class Singleton4 {

    private static Singleton4 instance;

    private Singleton4(){
    }

    public static synchronized Singleton4 getInstance(){
        /*使用时才创建*/
        if(instance == null){
            instance = new Singleton4();
        }
        return instance;
    }
}

5.双重检查(推荐使用)

为什么要双重检查?
如果直接锁里面判断是否存在再创建,会造成等待锁释放,影响效率

public class Singleton5 {

    //volatile 确保变量可见性
    private static volatile Singleton5 instance;

    private Singleton5(){

    }

    /*
     * 提供一个静态公有方法,当使用该方法时,才去创建instance
     * 解决线程安全问题,同时又解决了懒加载问题,保证了执行效率。
     * 
     */
    public static Singleton5 getInstance(){
        /*使用时才创建*/
        if(instance == null){                   
        //将没有持锁的其他线程隔离,保证只创建一次  
            synchronized (Singleton5.class){
                if (instance == null){
                    instance = new Singleton5();
                }
            }

        }
        return instance;
    }
}

6.枚举方式

推荐使用,而且解决各种问题
把枚举当成类使用

public static void main(String[] args) {
        Singleton singleton1 = Singleton.SINGLETON;
        singleton2.sayOK();
    }

    enum Singleton{
        SINGLETON;  //属性
        public void sayOK() {
            System.out.println("OK~");
        }
    }

工厂模式

简单工厂模式

if else 返回对应对象
缺点:违反开闭原则,如果类多的话,考虑抽象工厂模式

工厂方法模式

产品需要分类 例如: 都是北京披萨,但是有不同口味

//继承抽象类实现创建方法,根据传值返回对象 
public class BJOrderPizza extends OrderPizza {
 
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null; 
        if(orderType.equals("cheese")) {
          pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
          pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

抽象工厂模式

产品需要分类 例如: 都是北京披萨,但是有不同口味
每个产品都有自己的工厂

//一个抽象工厂模式的抽象层(接口) 
public interface AbsFactory {
    //让下面的工厂子类来 具体实现
    public Pizza createPizza(String orderType);
}

//这是工厂子类
public class BJFactory implements AbsFactory {
    
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null; 
        if(orderType.equals("cheese")) {
          pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")){ 
          pizza = new BJPepperPizza();
    }
    return pizza;
}

原型模式

实现clone方法

浅拷贝

父类Object实现的是浅拷贝

深拷贝

1.重写clone给成员对象赋值
2.通过序列化实现

//序列化
bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos);
oos.writeObject(this); //当前这个对象以对象流的方式输出

//反序列化
bis = new ByteArrayInputStream(bos.toByteArray()); ois = new ObjectInputStream(bis);
DeepProtoType copyObj = (DeepProtoType)ois.readObject();

构建者模式

1、产品(Product): 最终构建出来的对象

2、构建者(Builder): 实现抽象的构建方法

3、指挥者(Director):调用构建者的构建方法生成产品

适配器模式

总得来讲,就是对出参,入参的兼容

适用场景:

1、已经存在的类的接口不符合我们的需求;

2、创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;

3、在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类。

类适配器(将要适配的对象当做类,继承)

public static void main(String[] args) {
    System.out.println(" === 类适配器模式 ====");
    Phone phone = new Phone();
    phone.charging(new VoltageAdapter());
}
//被适配的类
public class Voltage220V {
    //输出 220V 的电压
    public int output220V() { 
        int src = 220;
        System.out.println("电压=" + src + "伏");
        return src;
    }
}
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
    @Override
    public int output5V() {
        //获取到 220V 电压
        int srcV = output220V();
        int dstV = srcV / 44 ; //转成 5v return dstV;
    }
}

对象适配器(将要适配的对象当做对象,传入)

//220V的电压转化为5V的电压
public static void main(String[] args) {
    System.out.println(" === 对象适配器模式 ===="); 
    Phone phone = new Phone();
    phone.charging(new VoltageAdapter(new Voltage220V()));
}

public class VoltageAdapter	implements IVoltage5V {
    private Voltage220V voltage220V; 
    //通过构造器,传入一个 Voltage220V 实例
    public VoltageAdapter(Voltage220V voltage220v) {
       this.voltage220V = voltage220v;
    }
    
    @Override
    public int output5V() {
    int dst = 0;
    if(null != voltage220V) {
        int src = voltage220V.output220V(); 
        System.out.println("使用对象适配器,进行适配~~");
        dst = src / 44;
        System.out.println("适配完成,输出的电压为=" + dst);
    }
    return dst;
    }
}

接口适配器(将要适配的对象当做接口,继承 )

较复杂,内部类去实现方法适配

桥接模式

抽取同类型对象的共性,区分出实现层,抽象层
总结: 共性的抽取,组合(小米+手机=小米手机)

//手机通过传入品牌去构造,品牌里面有同品牌手机共有方法
//实现层品牌,抽象层手机
public static void main(String[] args) {
    Phone phone1 = new FoldedPhone(new XiaoMi());
    phone1.open(); 
    phone1.call(); 
    phone1.close();
}
public interface Brand { 
    void open();
    void close(); 
    void call();
}
public class Vivo implements Brand {
    @Override
    public void open() {
        System.out.println(" Vivo 手机开机 ");
    }
    @Override
    public void close() {
        System.out.println(" Vivo 手机关机 ");
    }
    @Override
    public void call() {
        System.out.println(" Vivo 手机打电话 ");
    }
}
public abstract class Phone {
    private Brand brand;
    public Phone(Brand brand) {
        super();
     this.brand = brand;
    }
    protected void open() { 
        this.brand.open();
    }
    protected void close() { 
        brand.close();
    }
    protected void call() {
        brand.call();
    }
}
public class FoldedPhone extends Phone {
    public FoldedPhone(Brand brand) {
        super(brand);
    }
    public void open() { 
        super.open();
        System.out.println(" 折叠样式手机 ");
    }
    
    public void close() { 
        super.close();
        System.out.println(" 折叠样式手机 ");
    }
    
    public void call() { 
        super.call();
      System.out.println(" 折叠样式手机 ");
    }
}

装饰者模式

//1.抽象饮品 价格,描述属性;cost方法
//2.实际饮品继承抽象类,实现抽象cost方法
//3.装饰类继承抽象类,实现具体装饰(构造方法传入装饰类)

public static void main(String[] args){
    Drink order = new Espresso();
    order = new Milk(order);   
    order = new Chocolate(order);
}

public abstract class Drink {
    public String des; 
    private float price = 0.0f; 
    
    public String getDes() {
        return des;
    }
    public void setDes(String des) {
        this.des = des;
    }
    public float getPrice() { 
        return price
    }
    public void setPrice(float price) {
        this.price = price;
    }

    public abstract float cost();
}

public class Coffee	extends Drink {
    @Override
    public float cost() {
        return super.getPrice();
    }
}

public class Espresso extends Coffee {
    public Espresso() {
        setDes(" 意大利咖啡 "); 
        setPrice(6.0f);
    }
}

//单独抽一层通用装饰类实现子类装饰类的公用方法
public class Decorator extends Drink {
    private Drink obj;
    public Decorator(Drink obj) { //组合
     this.obj = obj;
    }

    @Override
    public float cost() {
        return super.getPrice() + obj.cost();
    }

    @Override
    public String getDes() {
       return des + " " + getPrice() + " && " + obj.getDes();
    }
}

public class Milk extends Decorator {
    public Milk(Drink obj) { 
      super(obj);
      setDes(" 牛 奶 "); 
      setPrice(2.0f);
    }
}

组合模式


public static void main(String[] args) {

    //从大到小创建对象 学校
    OrganizationComponent university = new University("清华大学", " 中国顶级大学 ");
    //创建 学院
    OrganizationComponent computerCollege = new College(" 计 算 机 学 院 ", " 计 算 机 学 院 "); 
    OrganizationComponent infoEngineercollege = new College("信息工程学院", " 信息工程学院 ");
    
    //创建各个学院下面的系(专业)
    computerCollege.add(new Department("软件工程", " 软件工程不错 ")); computerCollege.add(new Department("网络工程", " 网络工程不错 "));
    computerCollege.add(new Department("计算机科学与技术", " 计算机科学与技术是老牌的专业 "));
    infoEngineercollege.add(new Department("通信工程", " 通信工程不好学 ")); infoEngineercollege.add(new Department("信息工程", " 信息工程好学 "));
    //将学院加入到 学校
    university.add(computerCollege); university.add(infoEngineercollege);
    //university.print();
    infoEngineercollege.print();
}

public abstract class OrganizationComponent {
    private String name; // 名 字
    private String des; // 说 明
    protected	void add(OrganizationComponent organizationComponent) {
     throw new UnsupportedOperationException();
    }
    protected	void remove(OrganizationComponent organizationComponent) {
        throw new UnsupportedOperationException();
    }
    public OrganizationComponent(String name, String des) {
        super();
        this.name = name; 
        this.des = des;
    }
    public String getName() { 
        return name;
    }
    public void setName(String name) { 
        this.name = name;
    }
    public String getDes() {
      return des;
    }
    public void setDes(String des) {
        this.des = des;
    }
    protected abstract void print();
}

public class College extends OrganizationComponent {

    List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();
    public College(String name, String des) { super(name, des);
    }
    protected void add(OrganizationComponent organizationComponent) {
    }
    organizationComponents.add(organizationComponent);
    }
    protected void remove(OrganizationComponent organizationComponent) {
    }
    @Override
    public String getName() {
    }
    @Override
    public String getDes() {
    // TODO Auto-generated method stub return super.getDes();
    }
    @Override
    protected void print() {
    for (OrganizationComponent organizationComponent : organizationComponents) { 
        organizationComponent.print();
    }
}

public class University extends OrganizationComponent {
    List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();
    public University(String name, String des) {
         super(name, des);
    }
    protected void add(OrganizationComponent organizationComponent) {
         organizationComponents.add(organizationComponent);
    }
    protected void remove(OrganizationComponent organizationComponent) {
         organizationComponents.remove(organizationComponent);
    }
    @Override
    public String getName() {
    }
    @Override
    public String getDes() {
         return super.getDes();
    }
    @Override
    protected void print() {
     System.out.println("--------------" + getName() + "--------------");
    for (OrganizationComponent organizationComponent:organizationComponents) { 
            organizationComponent.print();
    }
}

外观模式

为系统中的一组接口,提供一个一致的界面

public static void main(String[] args) {
    HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();  
    homeTheaterFacade.ready();
    homeTheaterFacade.play();
    homeTheaterFacade.end();
}


public class HomeTheaterFacade {

    private TheaterLight theaterLight; 
    private Popcorn popcorn;
    private Stereo stereo;
    private Projector projector; 
    private Screen screen;
    private DVDPlayer dVDPlayer;

    //构造器
    public HomeTheaterFacade() { 
        super();
        this.theaterLight = TheaterLight.getInstance();
        this.popcorn = Popcorn.getInstance(); 
        this.stereo = Stereo.getInstance();
        this.projector = Projector.getInstance();
        this.screen = Screen.getInstance();
        this.dVDPlayer = DVDPlayer.getInstanc();
    }

    //操作分成 4  步
    public void ready() { 
        popcorn.on(); 
        popcorn.pop(); 
        screen.down();
        projector.on(); 
        stereo.on();
        dVDPlayer.on();
        theaterLight.dim();
    }
    public void play() { 
        dVDPlayer.play();
    }
    public void pause() {
        dVDPlayer.pause();
    }
    public void end() {
        popcorn.off();
        theaterLight.bright();
        screen.up();
        projector.off();
        stereo.off();
        dVDPlayer.off();
    }
}

public class DVDPlayer {
    private static DVDPlayer instance = new DVDPlayer();
    public static DVDPlayer getInstanc() { 
        return instance;
    }
    public void on() { 
        System.out.println(" dvd on ");
    }
    public void off() { 
        System.out.println(" dvd off ");
    }
    public void play() {
        System.out.println(" dvd is playing ");
    }
    public void pause() { 
        System.out.println(" dvd pause ..");
    }
}
public class Popcorn {
    private static Popcorn instance = new Popcorn();
    public static Popcorn getInstance() {
        return instance;
    }
    public void on() {
        System.out.println(" popcorn on ");
    }
    public void off() {
        System.out.println(" popcorn ff ");
    }
    public void pop() {
        System.out.println(" popcorn is poping	");
    }
}
等等很多设备......

享元模式

各种池技术
1)享元模式(Flyweight Pattern) 也叫 蝇量模式: 运用共享技术有效地支持大量细粒度的对象\

2)常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个\

3)享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。不需总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率\

4)享元模式经典的应用场景就是池技术了,String 常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式。***

//抽象网站
public abstract class WebSite {
    public abstract void use(User user);//抽象方法
}
//具体网站
public class ConcreteWebSite extends WebSite {
    //共享的部分,内部状态
    private String type = ""; //网站发布的形式(类型)
    //构造器
    public ConcreteWebSite(String type) {
        this.type = type;
    }
    @Override
    public void use(User user) {
    // TODO Auto-generated method stub
    System.out.println("网站的发布形式为:" + type + " 在使用中 .. 使用者是" + user.getName());
    }
}

// 网站工厂类,根据需要返回压一个网站
public class WebSiteFactory {
    //集合, 充当池的作用
    private HashMap<String, ConcreteWebSite> pool = new HashMap<>();
    //根据网站的类型,返回一个网站, 如果没有就创建一个网站,并放入到池中,并返回
    public WebSite getWebSiteCategory(String type) { 
        if(!pool.containsKey(type)) {
            //就创建一个网站,并放入到池中
            pool.put(type, new ConcreteWebSite(type));
            }
            return (WebSite)pool.get(type);
        }
        //获取网站分类的总数 (池中有多少个网站类型) public int getWebSiteCount() {
        return pool.size();
    }
}

代理模式

静态代理

//代理对象实现和被代理对象一样的接口方法
//1)优点:在不修改目标对象的功能前提下, 能通过代理对象对目标功能扩展
//2)缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类
//3)一旦接口增加方法,目标对象与代理对象都要维护
public interface ITeacherDao {
    void teach(); // 授课的方法
}
public class TeacherDao implements ITeacherDao {
    public void teach() {
      System.out.println(" 老师授课中	。。。。。");
    }
}
public class TeacherDaoProxy implements ITeacherDao{
    private ITeacherDao target;
    public TeacherDaoProxy(ITeacherDao target) { \
        this.target = target;
    }
    
    @Override
    public void teach() {
        System.out.println("开始代理完成某些操作。。。。。 ");
        target.teach();
        System.out.println("提交。。。。。");
    }
}

动态代理

JDK代理
1)代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用动态代理
2)代理对象的生成,是利用 JDK 的 API,动态的在内存中构建代理对象
3)动态代理也叫做:JDK 代理、接口代理

spring也是按照以下规则选择:
在代理对象不是借口类型或不是代理类时,指定proxyTargetClass=true后,执行CGLIB代理
代理对象是接口类型或是代理类,使用JDK代理
    
public static void main(String[] args) {
    //创建目标对象
    ITeacherDao target = new TeacherDao();
    //给目标对象,创建代理对象, 可以转成 ITeacherDao
    ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
    // proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
    System.out.println("proxyInstance=" + proxyInstance.getClass());
    //通过代理对象,调用目标对象的方法
    //proxyInstance.teach ();
    proxyInstance.sayHello(" tom ");
}

public class ProxyFactory {

    //维护一个目标对象 ,object
    private Object target;
    
    public ProxyFactory(Object target) {
        this.target = target;
    }
}
//给目标对象  生成一个代理对象
public Object getProxyInstance() {

//说明
/*
 *	
 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)
//1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
//2. Class<?>[] interfaces:  目标对象实现的接口类型,使用泛型方法确认类型
//3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行
的目标对象方法作为参数传入
*/
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
    new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("JDK 代理开始~~");
            //反射机制调用目标对象的方法
            Object returnVal = method.invoke(target, args);
            System.out.println("JDK 代理提交"); return returnVal;
        }
    });
}

Cglib代理(子类代理)
不支持final/static方法
1)静态代理和 JDK 代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是 Cglib 代理
2)Cglib 代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展, 有些书也将Cglib 代理归属到动态代理。
3)Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 java 类与实现 java 接口.它广泛的被许多 AOP 的框架使用,例如 Spring AOP,实现方法拦截
4)在 AOP 编程中如何选择代理模式:
1.目标对象需要实现接口,用 JDK 代理
2.目标对象不需要实现接口,用 Cglib 代理
5)Cglib 包的底层是通过使用字节码处理框架 ASM 来转换字节码并生成新的类

public static void main(String[] args) {
    //创建目标对象
    TeacherDao target = new TeacherDao();
    //获取到代理对象,并且将目标对象传递给代理对象
    TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();
    //执行代理对象的方法,触发 intecept  方法,从而实现 对目标对象的调用  
    String res = proxyInstance.teach();
    System.out.println("res=" + res);
}


public class ProxyFactory implements MethodInterceptor {
    //维护一个目标对象 
    private Object target;
    //构造器,传入一个被代理的对象
    public ProxyFactory(Object target) {
        this.target = target;
    }
    //返回一个代理对象:	是 target  对象的代理对象
    public Object getProxyInstance() {
        //1. 创建一个工具类
        Enhancer enhancer = new Enhancer();
        //2. 设置父类
        enhancer.setSuperclass(target.getClass());
        //3. 设置回调函数
        enhancer.setCallback(this);
        //4. 创建子类对象,即代理对象
        return enhancer.create();
    }
    //重写	intercept 方法,会调用目标对象的方法
    @Override
    public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
        System.out.println("Cglib 代理模式 ~~ 开始");
        Object returnVal = method.invoke(target, args); 
        System.out.println("Cglib 代理模式 ~~ 提交");   
        return returnVal;
    }
}

命令模式

优点

1)将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的 execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用。
2)容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令
3)容易实现对请求的撤销和重做
4)命令模式不足:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意
5)空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦。
命令模式经典的应用场景:界面的一个按钮都是一条命令、模拟 CMD(DOS 命令)订单的撤销/恢复、触发- 反馈机制

代码

//扩展的时候,增加一个对应的命令还有接收者

public static void main(String[] args) {
    //使用命令设计模式,完成通过遥控器,对电灯的操作
    //创建电灯的对象(接受者)
    LightReceiver lightReceiver = new LightReceiver();
    //创建电灯相关的开关命令
    LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
    LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
    //需要一个遥控器
    RemoteController remoteController = new RemoteController();
    
    //给我们的遥控器设置命令, 比如 no = 0  是电灯的开和关的操作
    remoteController.setCommand(0, lightOnCommand, lightOffCommand);
    
    System.out.println("--------按下灯的开按钮-----------"); 
    remoteController.onButtonWasPushed(0); 
    System.out.println("--------按下灯的关按钮-----------"); 
    remoteController.offButtonWasPushed(0); 
    System.out.println("--------按下撤销按钮-----------"); remoteController.undoButtonWasPushed();
    }
}

//命令接口
public interface Command {
    //执行动作(操作)
    public void execute();
    //撤销动作(操作) 
    public void undo();
}
//具体命令
public class LightOffCommand implements Command {
    // 聚 合
    LightReceiver LightReceiver light;
    // 构造器
    public LightOffCommand(LightReceiver light) {
        super();
        this.light = light;
    }
    @Override
    public void execute() {
        // 调用接收者的方法
        light.off();
    }
    @Override
    public void undo() {
        // 调用接收者的方法
        light.on();
    }
}
//接收者
public class LightReceiver {
    public void on() {
        System.out.println(" 电灯打开了.. ");
    }
    public void off() {
         System.out.println(" 电灯关闭了.. ");
    }
}
//调用者
public class RemoteController {
    // 开 按钮的命令数组
    Command[] onCommands; Command[] offCommands;
    // 执行撤销的命令
    Command undoCommand;
    // 构造器,完成对按钮初始化
    public RemoteController() {
        onCommands = new Command[5]; offCommands = new Command[5];
        for (int i = 0; i < 5; i++) {
             onCommands[i] = new NoCommand(); offCommands[i] = new NoCommand();
        }
    
    // 给我们的按钮设置你需要的命令
    public void setCommand(int no, Command onCommand, Command offCommand) { onCommands[no] = onCommand;
         offCommands[no] = offCommand;
    }
    // 按下开按钮
    public void onButtonWasPushed(int no) { // no 0
        // 找到你按下的开的按钮, 并调用对应方法
        onCommands[no].execute();
        // 记录这次的操作,用于撤销
        undoCommand = onCommands[no];
    }
    // 按下开按钮
    public void offButtonWasPushed(int no) {
        // 找到你按下的关的按钮, 并调用对应方法
        offCommands[no].execute();
        // 记录这次的操作,用于撤销
        undoCommand = offCommands[no];
    }
    // 按下撤销按钮
    public void undoButtonWasPushed() { undoCommand.undo();
    }
}

访问者模式

优点

优点
1)访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高
2)访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统
缺点
1)具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难
2)违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素
3)因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的.

代码

public abstract class Action {
    //得到男性 的测评
    public abstract void getManResult(Man man);
    //得到女的 测评
    public abstract void getWomanResult(Woman woman);
}
public class Fail extends Action {
    @Override
    public void getManResult(Man man) {
        System.out.println(" 男人给的评价该歌手失败 !");
    }
    
    @Override
    public void getWomanResult(Woman woman) {
        System.out.println(" 女人给的评价该歌手失败 !");
    }
}
public abstract class Person {
    public abstract void accept(Action action);
}
public class Man extends Person {
    @Override
    public void accept(Action action) {
        action.getManResult(this);
    }
}
//数据结构,管理很多人(Man , Woman) 
public class ObjectStructure {
    //维护了一个集合
    private List<Person> persons = new LinkedList<>();
    //增加到 list
    public void attach(Person p) {
        persons.add(p);
    }
    //移除
    public void detach(Person p) { 
        persons.remove(p);
    }
    
    //显示测评情况
    public void display(Action action) { 
        for(Person p: persons) {
              p.accept(action);
        }
    }
}

//调用
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.attach(new Man()); 
objectStructure.attach(new Woman());
//成功
Success success = new Success(); 
objectStructure.display(success);
Fail fail = new Fail(); 
objectStructure.display(fail);
Wait wait = new Wait();
objectStructure.display(wait);

迭代器模式

监听者模式

//1.把监听器都放到一个数组里面  2.传一个事件进去  3.遍历监听器执行
public class EventSource {
	//监听器列表,如果监听事件源的事件,注册监听器可以加入此列表
	private Vector<MonitorListener> listenerList = new Vector<>();
	
	//注册监听器
	public void addListener(MonitorListener eventListener) {
		listenerList.add(eventListener);
	}
	
	//删除监听器
	public void removeListener(MonitorListener eventListener) {
		int i = listenerList.indexOf(eventListener);
		if(i >= 0) {
			listenerList.remove(eventListener);
		}
	}
	
	//接受外部事件,通知所有的监听器
	public void notifyListenerEvents(PrintEvent event) {
//		Iterator<MonitorListener> iterator = listenerList.iterator();
//		while(iterator.hasNext()) {
//			MonitorListener monitorListener = (MonitorListener)iterator.next();
//			monitorListener.handleEvent(event);
//		}
		for(MonitorListener moniterListener : listenerList) {
			moniterListener.handleEvent(event);
		}
	}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑。2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 单例模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等3) 如果你想写出规范、漂亮的程序,就花时间来学习下设计模式吧课程内容和目标本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式:单例模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杭州水果捞|Java毕业设计成品

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值