用最简单的例子说明设计模式(二)之模版方法、策略模式、组合模式、观察者模式

模板方法模式

提供一个抽象类,将部分逻辑以具体方法或构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法(多态实现),从而实现不同的业务逻辑。

使用场景

1)多个子类有公有的方法,并且逻辑基本相同时

2)重要、复杂的算法,可以把核心算法设计为模板方法

3)重构时,模板方法模式是一个经常使用的模式

public abstract class AbstractWork {
     
    protected void getUp() {
        System.out.println("起床啦!");
    }
 
    protected abstract void goToWork();
 
    protected abstract void work();
 
    protected abstract void getOffWork();
 
    /*
     * TemplateMethod,大家都拥有共同的执行步骤
     */
    public final void newDay() {
        getUp();
        goToWork();
        work();
        getOffWork();
    }
 
}

public class BossWork extends AbstractWork {
     
    @Override
    protected void goToWork() {
        System.out.println("老板开车去上班");
    }
 
    @Override
    protected void work() {
        System.out.println("老板的分配工作给员工");
    }
 
    @Override
    protected void getOffWork() {
        System.out.println("老板开车去下班");
    }
 
}

public class StaffWork extends AbstractWork {
     
    @Override
    protected void goToWork() {
        System.out.println("员工做公交去上班");
 
    }
 
    @Override
    protected void work() {
        System.out.println("员工处理具体工作");
    }
 
    @Override
    protected void getOffWork() {
        System.out.println("员工做公交下班");
    }
 
}

public class Test {
    public static void main(String[] args) {
        BossWork bossWork = new BossWork();
        StaffWork staffWork = new StaffWork();
        bossWork.newDay();
        System.out.println("------------------------");
        staffWork.newDay();
    }
}

策略模式

定义了算法家庭,分别封装起来。让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

 一个类定义了多种行为,并且这些行为在这个类的方法中以多个条件语句的形式出现,那么可以使用策略模式避免在类中使用大量的条件语句。

public interface AbstractStrategy {
    //按距离来计算价格
    int calculatePrice(int km);
}

public class BusStrategy implements AbstractStrategy {
    @Override
    public int calculatePrice(int km) {
        int extraTotal = km - 10;
        int extraFactor = extraTotal / 5;
        int fraction = extraTotal % 5;
        int price = 1 + extraTotal % 5;
        return fraction > 0 ? ++price : price;
    }
}

public class TaxiStrategy implements AbstractStrategy {
    @Override
    public int calculatePrice(int km) {
        return km * 2;
    }
}

public class Context {

    private AbstractStrategy strategy;

    public void setStrategy(AbstractStrategy strategy) {
        this.strategy = strategy;
    }

    public int calclatePrice(int km) {
        return strategy.calculatePrice(km);
    }

    public static void main(String[] strings) {
        Context calculator = new Context();
        calculator.setStrategy(new BusStrategy());
//        calculator.setStrategy(new TaxiStrategy());
        System.out.println("公交车20km价格:" + calculator.calclatePrice(20));
    }

}

传统写法

    //PriceCalculator 类很明显的问题就是并不是单一职责,首先它承担计算公交车和地铁乘坐价格的职责,
    //另一个问题就是通过if-else的形式来判断使用哪种计算形式。当我们增加一种出行方式时,如出租车,
    //那么我们就需要在PriceCalculator 中增加一个方法来计算出租车出行的价格,并且在calculatePrice(int km, int type)函数增加一个判断
    public static class PriceCalculator {
        private static final int TAXI = 3;
        private static final int BUS = 1;
        private static final int SUBWAY = 2;

        public static void main(String[] strings) {
            PriceCalculator calculator = new PriceCalculator();
            System.out.println("做20km公交票价:" + calculator.calculatePrice(20, BUS));
            System.out.println("做20km地铁票价:" + calculator.calculatePrice(20, SUBWAY));
        }


        private int busPrice(int km) {
            return km * 1;
        }


        public int taxiPrice(int km) {
            return km * 7;
        }

        /**
         * 根据不同类型计算
         */
        int calculatePrice(int km, int type) {
            if (type == BUS) {
                return busPrice(km);
            } else if (type == SUBWAY) {
                return taxiPrice(km);
            }
            return 0;
        }
    }

组合模式

使用户对单个对象和组合对象的使用具有一致性。将对象组合成树形结构以表示“部分-整体”的层次结构。

Component : 组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。

Leaf : 表示叶节点对象。叶子节点没有子节点。

Composite : 定义枝节点行为,用来存储子部件,在 Component 接口中实现与子部件相关的操作。例如 Add 和 Remove

public abstract class File {

    private String name;

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

    //操作方法
    public String getName() {
        return name;
    }

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

    public abstract void watch();

    //组合方法
    public void add(File file) {
        throw new UnsupportedOperationException();
    }

    public void remove(File file) {
        throw new UnsupportedOperationException();
    }

    public File getChild(int position) {
        throw new UnsupportedOperationException();
    }
}

public class Folder extends File {

    private List<File> mFileList;

    public Folder(String name) {
        super(name);
        mFileList = new ArrayList<>();
    }

    @Override
    public void watch() {
        StringBuffer fileName = new StringBuffer();
        for (File file : mFileList) {
            fileName.append(file.getName() + ";");
        }
       
          System.out.println("组合模式:这是一个叫" + getName() + "文件夹,包含" + mFileList.size() + "个文件,分别是:" + fileName);

    }

    @Override
    public void add(File file) {
        mFileList.add(file);
    }

    @Override
    public void remove(File file) {
        mFileList.remove(file);
    }

    @Override
    public File getChild(int position) {
        return mFileList.get(position);
    }
}

public class TextFile extends File {

    public TextFile(String name) {
        super(name);
    }

    @Override
    public void watch() {
        System.out.println("组合模式:这是一个叫" + getName() + "文本文件");
    }
}

public class testComposite {
    public static void main(String[] strings) {
        TextFile textFileA = new TextFile("a.txt");
        TextFile textFileB = new TextFile("b.txt");
        TextFile textFileC = new TextFile("c.txt");

        textFileA.watch();
    //  textFileA.add(textFileB);//调用会抛我们在抽象接口中写的异常

        Folder folder = new Folder("学习资料");
        folder.add(textFileA);
        folder.add(textFileB);
        folder.add(textFileC);
        folder.watch();
        folder.getChild(1).watch();
        
        Folder folder1 = new Folder("个人资料");
        folder1.add(textFileA);
        folder1.add(textFileB);
        //可以随便组合
        Folder folder2 = new Folder("D盘资料");
        folder2.add(folder);
        folder2.add(folder1);
      
    }

}

观察者模式

定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆可得到通知并被自动更新。

观察者模式在android中的实际运用:回调模式

回调模式:实现了抽象类/接口的实例实现了父类的提供的抽象方法后,将该方法交还给父类来处理。

例如:通过 setOnClickListener() 方法,Button 持有 OnClickListener 的引用(这一过程没有在图上画出);当用户点击时,Button 自动调用 OnClickListener 的 onClick() 方法。另外,如果把这张图中的概念抽象出来(Button(view) -> 被观察者、OnClickListener -> 观察者、setOnClickListener() -> 订阅,onClick() -> 事件),就由专用的观察者模式(例如只用于监听控件点击)转变成了通用的观察者模式。

public class ObserverPattern {

    public interface Observer {
        void update(String state);
    }

    public class ConcreteObserver implements Observer {
        // 观察者状态
        private String observerState;

        @Override
        public void update(String state) {
            // 更新观察者状态,让它与目标状态一致
            observerState = state;
            System.out.println("ConcreteObserver State :" + observerState);
        }
    }

    /**
     * 抽象订阅者(目标者)
     * 被观察者
     *
     */
    public abstract class Subject {

        // 保存注册的观察者对象
        private List<Observer> mObservers = new ArrayList<>();

        //注册观察者对象
        public void attach(Observer observer) {
            mObservers.add(observer);
            System.out.println("Attached an observer");
        }

        //注销观察者对象
        public void detach(Observer observer) {
            mObservers.remove(observer);
        }

        // 通知所有注册的观察者对象
        public void nodifyObservers(String newState) {
            for (Observer observer : mObservers) {
                observer.update(newState);
            }
        }
    }

    public class ConcreteSubject extends Subject {

        private String state;

        public String getState() {
            return state;
        }

        public void change(String newState) {
            state = newState;
            System.out.println("ConcreteSubject State:" + state);
            //状态发生改变,通知观察者
            nodifyObservers(state);
        }
    }

    public static void main(String[] args) {
        ObserverPattern observerPattern = new ObserverPattern();
        ConcreteSubject concreteSubject = observerPattern.new ConcreteSubject();
        Observer observer1 = observerPattern.new ConcreteObserver();
        Observer observer2 = observerPattern.new ConcreteObserver();
        // 将观察者对象注册到目标对象上
        concreteSubject.attach(observer1);
        concreteSubject.attach(observer2);
        // 改变目标对象的状态
        concreteSubject.change("I change");
    }
}

相关源码:

https://github.com/peiniwan/DesignPattern.git

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

Go语言如何提高快排的效率

快排利用分治的思想,这里数组/切片分为两个部分,左边比哨兵小,右边比哨兵大,然后递归执行快排函数,这里有个很重要的因素是如果递归调用的时候用协程执行,左半部分...

3698
来自专栏chenjx85的技术专栏

leetcode-136-Single Number

2394
来自专栏Spark学习技巧

Flink DataStream编程指南

Flink程序是执行分布式集合转换(例如,filtering, mapping, updating state, joining, grouping, defi...

1.7K7
来自专栏zaking's

js算法初窥04(算法模式01-递归)

1232
来自专栏HansBug's Lab

3038: 上帝造题的七分钟2

3038: 上帝造题的七分钟2 Time Limit: 3 Sec  Memory Limit: 128 MB Submit: 662  Solved: 302...

2854
来自专栏JackieZheng

初探JavaScript(四)——作用域链和声明提前

前言:最近恰逢毕业季,千千万万的学生党开始步入社会,告别象牙塔似的学校生活。往往在人生的各个拐点的时候,情感丰富,感触颇深,各种对过去的美好的总结,对未来的展望...

1965
来自专栏xingoo, 一个梦想做发明家的程序员

【设计模式】—— 适配器模式Adapter

  模式意图   如果已经有了一种类,而需要调用的接口却并不能通过这个类实现。因此,把这个现有的类,经过适配,转换成支持接口的类。   换句话说,就是把一种现有...

18810
来自专栏IMWeb前端团队

简洁的javascript编码(一)--变量、函数

本文作者:IMWeb jaychen 原文出处:IMWeb社区 未经同意,禁止转载 ? 一、变量 使用语义化的变量名称 Bad cons...

2479
来自专栏Java爬坑系列

【JAVA零基础入门系列】Day3 Java基本数据类型

  前两篇已经将开发环境搭建完成,如果你已经按之前的教程按部就班的完成了部署,那么世界上最优秀的编程语言之一和世界上最优秀的IDE之一已经出现在你的电脑上(此处...

2128
来自专栏進无尽的文章

如何优化冗长的条件语句

【1】尽量少用 else 尽量多用 if reture 的语法方式。 【2】字典的逻辑对应转化作用。 【3】用多态替代条件语句 【4】策略模式,继承重写,...

1521

扫码关注云+社区

领取腾讯云代金券