认真看书,多动手写demo,就能理解的啦~~加油.
java的设计模式大体上分为三大类:
- 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
- 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
- 行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计模式遵循的原则有6个:
1、开闭原则(Open Close Principle)
对扩展开放,对修改关闭。
2、里氏代换原则(Liskov Substitution Principle)
只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
使用多个隔离的借口来降低耦合度。
5、迪米特法则(最少知道原则)(Demeter Principle)
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改。
一: 创建型模式
1/单例模式
定义: 确保某一个类只有一个实例,并且提供一个全局访问点。
对于安卓,基本低并发,所以它的各种写法都可以用.
用这个稳的:
/**
*第一加载Singleton类时,并没有实例化,需要调用getInstance()后才会导致Singleton实例化.
*/
public class Singleton{
private Singleton(); // 私有
public static Singleton getInstance(){
return SingletonHolder.sInstance; //用SingletonHolder来持有Singleton的实例.
}
/**
* Singleton的持有类
* 内部静态类
*/
private static class Singleton{
private static final Singleton sInstance = new Singleton() ;
}
}
2/建造者Builder模式
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。适用: 那些产品对象的内部结构比较复杂。
举个例子:
public class Person {
private String name;
private int height;
public Person(Builder builder) {
= ;
this.height = builder.height;
}
static class Builder{
private String name;
private int height;
public Builder name(String name) {
= name;
return this; //关键之处, 返回Builder 自身
}
public Builder height(int height) {
this.height = height;
return this;
}
public Person build(){
return new Person(this); //返回 Person 实例
}
}
}
//-------------测试----------------
public class T1 {
public static void main(String[] args) {
Person.Builder builder = new Person.Builder();
Person person = builder.height(12)
.name("大王")
.phone("10086")
.sex("雄性")
.weight(120)
.build();
}
}
3/原型模式 (克隆)
定义:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
一句话概括: 当 new 新建对象费资源( 耗时/创建成本高 ) 时,或者需要保护 源对象 , 可以考虑使用 clone。
场景:
在我们应用程序可能有某些对象的结构比较复杂,但是我们又需要频繁的使用它们,如果这个时候我们来不断的新建这个对象势必会大大损耗系统内存的,这个时候我们需要使用原型模式来对这个结构复杂又要频繁使用的对象进行克隆。
举个例子:
public class Document implements Cloneable { //需要实现 Cloneable 接口 (PS:这里是浅拷贝)
private String mText; //文本
private ArrayList<String> mImages = new ArrayList<>();//图片
public String getText() { return mText; }
public void setText(String text) { mText = text; }
public ArrayList<String> getImages() { return mImages; }
public void setImages(ArrayList<String> images) { mImages = images; }
@Override
protected Document clone() {
try {
Document doc = (Document)super.clone();
doc.mText = this.mText;
doc.mImages = this.mImages;
return doc;
}catch (CloneNotSupportedException e){
//dosomething
}
return null;
}
}
//---------------测试------------------
public class Test {
public static void main(String[] args) {
Document doc = new Document();
ArrayList<String> images = new ArrayList<String>();images.add("卡哇伊.jpg");images.add("滑稽.jpg");
doc.setText("123");
doc.setImages(images);
System.out.println("原始文档的文本:"+doc.getText());
Document doc2 = doc.clone();
System.out.println("拷贝原始文档后, 文档2修改前的文本:"+doc2.getText());
doc2.setText("abc"); //修改doc2
System.out.println("文档2修改后的文本:"+doc2.getText());
System.out.println("文档2修改后,原始文档的文本:"+doc.getText());
ps: "这里改变 ArrayList 内容的话, 源对象 会 受到影响 , 解决方法是 使用 深拷贝 "
}
}
//---------------输出------------------
原始文档的文本:123
拷贝原始文档后, 文档2修改前的文本:123
文档2修改后的文本:abc
文档2修改后,原始文档的文本:123
//深拷贝 看这里
@Override
protected Document clone() {
Document doc = (Document)super.clone();
doc.mText = this.mText;
//对mImages进行深度拷贝, 这样修改mImages内容后,源对象不受影响
doc.mImages = (ArrayList<String>)this.mImages.clone();
return doc;
}
4/工厂方法 (常用)
作为抽象工厂模式的孪生兄弟,工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,也就是说工厂方法模式让实例化推迟到子类。
工厂方法模式非常符合“开闭原则”,当需要增加一个新的产品时,我们只需要增加一个具体的产品类和与之对应的具体工厂即可,无须修改原有系统。同时在工厂方法模式中用户只需要知道生产产品的具体工厂即可,无须关系产品的创建过程,甚至连具体的产品类名称都不需要知道。虽然他很好的符合了“开闭原则”,但是由于每新增一个新产品时就需要增加两个类,这样势必会导致系统的复杂度增加。
工厂方法模式UML类图:
图解: 具体工厂A(实现了抽象工厂)引用具体产品A(实现了抽象产品)
我的理解: "让 具体的工厂来决定制造具体的产品"
举个例子:
"抽象工厂"
public abstract class Factory {
public abstract Product createProduct();
}
"具体工厂A" 让工厂子类决定 实例化 某个产品类
public class FactoryA extends Factory {
@Override
public Product createProduct() {
return new ProductA(); 具体工厂A 制作 具体产品A
}
}
"具体工厂B" 这里是FactoryB 制造 产品B
public class FactoryB extends Factory {
@Override
public Product createProduct() {
return new ProductB(); 具体工厂A 制作 具体产品A
}
}
"抽象产品"
public abstract class Product {
public abstract void make();
}
public class ProductA extends Product {
@Override
public void make() {
System.out.println("make ProductA");
}
}
public class FTest1 {
public static void main(String[] args) {
Factory factoryA = new FactoryA();
Product productA = factoryA.createProduct();
productA.make(); //工厂A 制作 产品A
//....其他工厂的制造,比如工厂B 制作 产品B
Factory factoryB = new FactoryB();
Product productB = factoryB.createProduct();
productB.make(); //工厂B 制作 产品B
}
}
5/抽象工厂模式
所谓抽象工厂模式就是提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类。
他允许客户端使用抽象的接口来创建一组相关的产品,而不需要关系实际产出的具体产品是什么。这样一来,客户就可以从具体的产品中被解耦。它的优点是隔离了具体类的生成,使得客户端不需要知道什么被创建了,而缺点就在于新增新的行为会比较麻烦,因为当添加一个新的产品对象时,需要更加需要更改接口及其下所有子类。
工厂方法 和 抽象工厂模式 的UML类图 比较
工厂方法:
抽象工厂模式
我的理解:
将同种类的工厂抽象为一个抽象工厂, 子类工厂 生产 具体的(多种类的)产品们;
将同种类的产品抽象为一个抽象产品, 子类 实现 具体的 产品;
举个例子(附带代码):
手机软件有 安卓系统 或者 ios系统 的软件, 它们都有制作 短信/拨号软件的功能, 所以我们可以将抽象出一个 软件工厂, 抽象制作 短信软件 和 拨号软件的方法, 由具体的工厂去实现;
抽象的软件工厂:
======>安卓软件工厂: 生产安卓端的短信软件 和 拨号软件;
======>IOS软件工厂: 生产IOS端的短信软件 和 拨号软件;
安卓、IOS两端的xx短信软件 , 它们属于同种功能的软件,只是实现方式不一样,所以 可以抽象为 短信软件 类; 由子类自己去具体实现;拨号软件同理;
抽象的短信软件 的产品:
======>安卓短信软件 和 IOS短信软件;
抽象的拨号软件 的产品:
======>安卓短信软件 和 IOS短信软件;
"抽象的软件工厂"
public abstract class SoftFactory {
public abstract SMS createSMS();
public abstract Dialer createDialer();
}
"子类:安卓软件工厂"
public class AndroidFactory extends SoftFactory {
@Override
public SMS createSMS() {
return new AndroidSMS(); //具体实现
}
@Override
public Dialer createDialer() {
return new AndroidDialer();
}
"子类:IOS软件工厂"
public class IOSFactory extends SoftFactory {
@Override
public SMS createSMS() {
return new IOSSMS();
}
@Override
public Dialer createDialer() {
return new IOSDialer();
}
}
"抽象的短信软件"
public abstract class SMS {
public abstract void makeSms();
}
"子类:安卓短信软件"
public class AndroidSMS extends SMS {
@Override
public void makeSms() {
System.out.println("制作安卓的短信软件");
}
}
.....同理
}
------------测试------------------
public class T1 {
public static void main(String[] args) {
//安卓软件
AndroidFactory android = new AndroidFactory();
android.createSMS().makeSms();
android.createDialer().makeDialer();
//IOS软件
IOSFactory ios = new IOSFactory();
ios.createSMS().makeSms();
ios.createDialer().makeDialer();
}
}
------------输出------------------
------安卓软件工厂------
制作安卓的短信软件
制作安卓的拨号软件
------IOS软件工厂------
制作IOS的短信软件
制作IOS的拨号软件
----------------------------------
二: 行为型模式
1/策略模式 (拥有多个方案进行选择时,避开if-else)
我们知道一件事可能会有很多种方式来实现它,但是其中总有一种最高效的方式,在软件开发的世界里面同样如此,我们也有很多中方法来实现一个功能,但是我们需要一种简单、高效的方式来实现它,使得系统能够非常灵活,这就是策略模式。
所以策略模式就是定义了算法族,分别封装起来,让他们之前可以互相转换,此模式然该算法的变化独立于使用算法的客户。
在策略模式中它将这些解决问题的方法定义成一个算法群,每一个方法都对应着一个具体的算法,这里的一个算法我就称之为一个策略。虽然策略模式定义了算法,但是它并不提供算法的选择,即什么算法对于什么问题最合适这是策略模式所不关心的,所以对于策略的选择还是要客户端来做。客户必须要清楚的知道每个算法之间的区别和在什么时候什么地方使用什么策略是最合适的,这样就增加客户端的负担。
同时策略模式也非常完美的符合了"开闭原则",用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。但是一个策略对应一个类将会是系统产生很多的策略类。
"将多种方法归类, 抽象为一个接口, 具体方法实现这个接口"
public interface CalculateStrategy {
int cacultePrice(int km);
}
public class BusStrategy implements CalculateStrategy {
@Override
public int cacultePrice(int km) {
//bus的相关计算
//.....省略
return 5;
}
}
public class SubwayStrategy implements CalculateStrategy {
@Override
public int cacultePrice(int km) {
//Subway的相关计算
//.....省略
return 10;
}
}
public class TaxiStrategy implements CalculateStrategy {
@Override
public int cacultePrice(int km) {
//Taxi的相关计算
//.....省略
return 30;
}
}
"将策略抽象类传进来"
public class TranficCalculate {
CalculateStrategy mStrategy;
public TranficCalculate(CalculateStrategy strategy) {
mStrategy = strategy;
}
public int calculatePrice(int km){
return mStrategy.cacultePrice(km);
}
}
public class T2 {
public static void main(String[] args) {
"出行 , 选择 不用再if-else了, 传入具体的策略 即可"
TranficCalculate calculator = new TranficCalculate(new BusStrategy());
System.out.println(calculator.calculatePrice(20));
}
}
2/ 状态模式 (可参考wifi状态…)
在很多情况下我们对象的行为依赖于它的一个或者多个变化的属性,这些可变的属性我们称之为状态,也就是说行为依赖状态,即当该对象因为在外部的互动而导致他的状态发生变化,从而它的行为也会做出相应的变化。对于这种情况,我们是不能用行为来控制状态的变化,而应该站在状态的角度来思考行为,即是什么状态就要做出什么样的行为。这个就是状态模式。
所以状态模式就是允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
在状态模式中我们可以减少大块的if…else语句,它是允许态转换逻辑与状态对象合成一体,但是减少if…else语句的代价就是会换来大量的类,所以状态模式势必会增加系统中类或者对象的个数。
同时状态模式是将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。但是这样就会导致系统的结构和实现都会比较复杂,如果使用不当就会导致程序的结构和代码混乱,不利于维护。
一句话总结:状态发生改变,行为发生对应的变化。
状态模式和策略模式对比:
状态模式的行为:平行的、不可替换的;
策略模式的行为:彼此独立、可互相替换。
状态模式UML类图 ↓
"--------------------不同状态对应着不同的行为------------"
public interface TVState { //遥控的一些行为
void nextChannel();
void prevChannel();
void turnup();
void turnDown();
}
public class PowerOnState implements TVState {
@Override
public void nextChannel() {
System.out.println("下一个频道");
}
@Override
public void prevChannel() {
System.out.println("上一个频道");
}
@Override
public void turnup() {
System.out.println("增大音量");
}
@Override
public void turnDown() {
System.out.println("减小音量");
}
}
public class PowerOffState implements TVState {
@Override
public void nextChannel() {
System.out.println("关机了无操作");
}
@Override
public void prevChannel() {
System.out.println("关机了无操作");
}
@Override
public void turnup() {
System.out.println("关机了无操作");
}
@Override
public void turnDown() {
System.out.println("关机了无操作");
}
}
public interface PowerController {
void powerOn();
void powerOff();
}
public class TvController implements PowerController {
private TVState mTVState;
private void setTVState(TVState TVState) {
mTVState = TVState;
}
@Override
public void powerOn() {
setTVState(new PowerOnState());
System.out.println("-----开机了-----");
}
@Override
public void powerOff() {
setTVState(new PowerOffState());
System.out.println("-----关机了-----");
}
public void nextChannel(){
mTVState.nextChannel();
}
public void prevChannel(){
mTVState.prevChannel();
}
public void turnDown(){
mTVState.turnup();
}
public void turnup(){
mTVState.turnup();
}
}
---------------------------------测试-------------------------------------
public class Test11 {
public static void main(String[] args) {
TvController controller = new TvController();
//开机
controller.powerOn();
//开机后的遥控操作
controller.nextChannel();
controller.prevChannel();
controller.turnup();
controller.turnDown();
//关机
controller.powerOff();
//关机后的遥控操作
controller.nextChannel();
}
}
---------------------------------日志输出---------------------------------
-----开机了-----
下一个频道
上一个频道
增大音量
增大音量
-----关机了-----
关机了无操作
3/责任链模式
请求沿着对象链传递。该将对象组成一条链,发送者将请求发给链的第一个接收者,并且沿着这条链传递,直到有一个对象来处理它或者直到最后也没有对象处理而留在链末尾端。
避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止,这就是职责链模式。在职责链模式中,使得每一个对象都有可能来处理请求,从而实现了请求的发送者和接收者之间的解耦。同时职责链模式简化了对象的结构,它使得每个对象都只需要引用它的后继者即可,而不必了解整条链,这样既提高了系统的灵活性也使得增加新的请求处理类也比较方便。但是在职责链中我们不能保证所有的请求都能够被处理,而且不利于观察运行时特征。
责任链UML:
"重点在这个抽象类"
public abstract class AbstractLeader {
public AbstractLeader nextLeader;
public abstract int limit();
public void handlerRequst(int money){ //子类实现后,调用的就是这个handlerRequst, 进行判断处理.
if(money<=limit()){
handler(money);//当前子类处理
}else {
nextLeader.handlerRequst(money);//交给nextLeader处理,调用的是下一个子类的handlerRequst
}
}
public abstract void handler(int money); //子类具体实现该方法
}
public class Boss extends AbstractLeader {
@Override
public int limit() {
return 50000;
}
@Override
public void handler(int money) {
System.out.println("我是老板,处理了:"+money+"钱");
}
}
public class Manager extends AbstractLeader {
@Override
public int limit() {
return 5000;
}
@Override
public void handler(int money) {
System.out.println("我是经理,处理了:"+money+"钱");
}
}
public class TeamLeader extends AbstractLeader {
@Override
public int limit() {
return 1000;
}
@Override
public void handler(int money) {
System.out.println("我是组长,处理了:"+money+"钱");
}
}
-------------------测试---------------------
public class Test11 {
public static void main(String[] args) {
TeamLeader teamLeader = new TeamLeader();
Manager manager = new Manager();
Boss boss = new Boss();
teamLeader.nextLeader=manager;
manager.nextLeader=boss;
teamLeader.handlerRequst(4000);
}
}
-----------日志输出------------
//组长处理不了,交给了上级领导---经理
我是经理,处理了:4000钱
4/命令模式
有些时候我们想某个对象发送一个请求,但是我们并不知道该请求的具体接收者是谁,具体的处理过程是如何的,们只知道在程序运行中指定具体的请求接收者即可,对于这样将请求封装成对象的,我们称之为命令模式。所以命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。同时命令模式支持可撤销的操作。
命令模式可以将请求的发送者和接收者之间实现完全的解耦,发送者和接收者之间没有直接的联系,发送者只需要知道如何发送请求命令即可,其余的可以一概不管,甚至命令是否成功都无需关心。同时我们可以非常方便的增加新的命令,但是可能就是因为方便和对请求的封装就会导致系统中会存在过多的具体命令类。
命令模式UML:
"这里根据UML类图写个简单的例子吧,具体化(赋予实物)应该也是同理的."
"将 请求/命令 封装成对象"
public abstract class Command {
public abstract void excute();
}
public class Recevier {
public void action(String what){
System.out.println("接收者,得到的参数:"+what);
}
}
public class ConcrectCommand extends Command {
Recevier recevier; // 接收者
public ConcrectCommand(Recevier recevier) {
this.recevier = recevier;
}
@Override
public void excute() {
recevier.action("具体命令参数: 开灯");
}
}
"调用者"
public class Invoker {
Command command;
public Invoker(Command command) {
this.command=command;
}
public void action(){
command.excute();
}
}
---------------测试---------------
public class T1 {
public static void main(String[] args) {
Recevier recevier = new Recevier();
ConcrectCommand command = new ConcrectCommand(recevier);
Invoker invoker = new Invoker(command);
invoker.action(); //执行命令
"命令模式可以将请求的发送者和接收者之间实现完全的解耦,"
"发送者和接收者之间没有直接的联系,发送者只需要知道如何发送请求命令即可,"
" 其余的可以一概不管,甚至命令是否成功都无需关心。"
}
}
5/观察者模式
观察者模式定义了对象之间的一对多依赖关系,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并且自动更新。
在这里,发生改变的对象称之为观察目标,而被通知的对象称之为观察者。一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,所以么可以根据需要增加和删除观察者,使得系统更易于扩展。所以观察者提供了一种对象设计,让主题和观察者之间以松耦合的方式结合。
插入一个Observable的源码解析:
观察者模式UML类图:
使用java.util下的观察者
/**
* 被观察者 (它 发送/通知/更新 to 观察者)
* */
public class Sender extends Observable {
public void post(String arg){
setChanged();
notifyObservers(arg);
}
}
/**
* 接收者
*/
public class Recevicer implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("收到通知:"+arg);
}
}
public class T22 {
public static void main(String[] args) {
Sender sender = new Sender();
sender.addObserver(new Recevicer());
sender.post("2018年9月29日,快放国庆啦!!~~~~");
}
}
6/备忘录模式
后悔药人人都想要,但是事实却是残酷的,根本就没有后悔药可买,但是也不仅如此,在软件的世界里就有后悔药!备忘录模式就是一种后悔药,它给我们的软件提供后悔药的机制,通过它可以使系统恢复到某一特定的历史状态。
所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它实现了对信息的封装,使得客户不需要关心状态保存的细节。保存就要消耗资源,所以备忘录模式的缺点就在于消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
备忘录模式UML类图
public class Game {
private int level = 0; // 等级
private int checkpoint = 1; //关卡
private String name = "admin"; //角色名
//玩游戏
public void play(){
this.level=100;
this.checkpoint=59;
= "小明";
System.out.println("玩游戏:"+toString());
}
//退出游戏
public void quit(){
System.out.println("退出游戏:");
}
public Memoto createMemoto(){
Memoto memoto = new Memoto();
memoto.checkpoint=this.checkpoint;
memoto.level=this.level;
memoto.name=;
return memoto;
}
public void restore(Memoto memoto){
this.checkpoint = memoto.checkpoint;
this.level = memoto.level;
= memoto.name;
System.out.println("恢复游戏:"+toString());
}
@Override
public String toString() {
return "Game{" +
"level=" + level +
", checkpoint=" + checkpoint +
", name='" + name + '\'' +
'}';
}
}
public class Memoto {
public int level = 0; // 等级
public int checkpoint = 1; //关卡
public String name = "admin"; //角色名
}
/**
* 管理存档 这个除了管理单个Memoto ,也可以是一个Memoto 集合
* */
public class CareTaker {
Memoto mMemoto;
//存档
public void archive(Memoto memoto) {
this.mMemoto = memoto;
}
public Memoto getMemoto() {
return mMemoto;
}
}
public class T111 {
public static void main(String[] args) {
Game game = new Game();
CareTaker careTaker = new CareTaker();
//玩游戏
game.play();
//存档
careTaker.archive(game.createMemoto()); //存档存到careTaker
//退出游戏
game.quit();
//重进游戏,新建了一个游戏, 假设careTaker没被干掉
Game newGame = new Game();
//恢复存档
newGame.restore(careTaker.getMemoto());
}
}
7/迭代器模式
对于迭代在编程过程中我们经常用到,能够游走于聚合内的每一个元素,同时还可以提供多种不同的遍历方式,这就是迭代器模式的设计动机。在我们实际的开发过程中,我们可能会需要根据不同的需求以不同的方式来遍历整个对象,但是我们又不希望在聚合对象的抽象接口中充斥着各种不同的遍历操作,于是我们就希望有某个东西能够以多种不同的方式来遍历一个聚合对象,这时迭代器模式出现了。
何为迭代器模式?所谓迭代器模式就是提供一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示。迭代器模式是将迭代元素的责任交给迭代器,而不是聚合对象,我们甚至在不需要知道该聚合对象的内部结构就可以实现该聚合对象的迭代。
通过迭代器模式,使得聚合对象的结构更加简单,它不需要关注它元素的遍历,只需要专注它应该专注的事情,这样就更加符合单一职责原则了。
迭代器模式UML类图
迭代器的接口
public interface MyIterator {
boolean hasNext();
Object next();
}
具体迭代器,这里是数组
public class ArrayIterator<T> implements MyIterator {
private String[] array;
private int position;
public ArrayIterator(String[] array) {
this.array = array;
}
@Override
public boolean hasNext() {
return !(position>array.length-1 || array[position]==null);
}
@Override
public Object next() {
return array[position++];
}
}
具体迭代器,这里是列表
public class ListIterator<T> implements MyIterator {
private List<T> array;
private int position;
public ListIterator(List<T> args) {
this.array = args;
}
@Override
public boolean hasNext() {
return !(position>array.size()-1 || array.get(position)==null);
}
@Override
public Object next() {
return array.get(position++);
}
}
获取迭代器的接口,重点
public interface Company {
MyIterator iterator();
}
实现接口,获取具体迭代器
public class ACompany implements Company {
private List<String> list = new ArrayList<>();
public ACompany() {
list.add("大王1");
list.add("大王2");
}
@Override
public MyIterator iterator() {
return new ListIterator<>(list); //重点
}
}
实现接口,获取具体迭代器
public class BCompany implements Company {
private String[] array = new String[4];
public BCompany() {
array[0]="呵呵1";
array[1]="呵呵2";
array[2]="呵呵3";
}
public String[] getData(){
return array;
}
@Override
public MyIterator iterator() {
return new ArrayIterator<>(array);
}
}
测试
public class T {
public static void main(String[] args) {
ACompany aCompany = new ACompany();
BCompany bCompany = new BCompany();
//aCompany.iterator() 获取具体迭代器
check(aCompany.iterator()); //将具体迭代器传入
check(bCompany.iterator());
}
private static void check(MyIterator iterator){
//遍历
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
8/模板模式
有些时候我们做某几件事情的步骤都差不多,仅有那么一小点的不同,在软件开发的世界里同样如此,如果我们都将这些步骤都一一做的话,费时费力不讨好。所以我们可以将这些步骤分解、封装起来,然后利用继承的方式来继承即可,当然不同的可以自己重写实现嘛!这就是模板方法模式提供的解决方案。
所谓模板方法模式就是在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模板方法模式就是基于继承的代码复用技术的。在模板方法模式中,我们可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中。也就是说我们需要声明一个抽象的父类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法让子类来实现剩余的逻辑,不同的子类可以以不同的方式来实现这些逻辑。所以模板方法的模板其实就是一个普通的方法,只不过这个方法是将算法实现的步骤封装起来的。
public abstract class AbComputer {
public void checkHardware(){
System.out.println("检查硬件");
}
public void loadOS(){
System.out.println("进入系统");
}
public void login(){
System.out.println("进入系统");
}
public void show(){
System.out.println("显示桌面");
}
public final void startup(){
System.out.println("---开机...---");
checkHardware();
loadOS();
login();
show();
System.out.println("---开机完成--");
}
}
public class NormalComputer extends AbComputer {
public NormalComputer() {
System.out.println("菜鸟的电脑");
}
@Override
public void login() {
System.out.println("没有密码,直接登录喔");
}
}
public class ProComputer extends AbComputer {
public ProComputer() {
System.out.println("专业的电脑");
}
@Override
public void login() {
System.out.println("需要键入密码才能登录");
}
}
public class T {
public static void main(String[] args) {
AbComputer computer = new ProComputer();
computer.startup();
}
}
9/访问者模式
访问者模式俗称23大设计模式中最难的一个。除了结构复杂外,理解也比较难。在我们软件开发中我们可能会对同一个对象有不同的处理,如果我们都做分别的处理,将会产生灾难性的错误。对于这种问题,访问者模式提供了比较好的解决方案。访问者模式即表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式。同时我们还需要明确一点那就是访问者模式是适用于那些数据结构比较稳定的,因为他是将数据的操作与数据结构进行分离了,如果某个系统的数据结构相对稳定,但是操作算法易于变化的话,就比较适用适用访问者模式,因为访问者模式使得算法操作的增加变得比较简单了。
"抽象访问者"
public interface Visitor {
void visit(Engineer engineer);
void visit(Manager manager);
}
"具体访问者"
public class CTOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("工程师:"++",代码行数:"+engineer.getCodeLines());
}
@Override
public void visit(Manager manager) {
System.out.println("经理:"++",新产品量:"+manager.getProducts());
}
}
"具体访问者"
public class CEOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("工程师:"++",KPI:"+engineer.KPI);
}
@Override
public void visit(Manager manager) {
System.out.println("经理:"++",KPI:"+manager.KPI+",新产品量:"+manager.getProducts());
}
}
"抽象元素"
public abstract class Staff {
public String name;
public int KPI;
public Staff(String name) {
= name;
this.KPI = new Random().nextInt(10);
}
public abstract void accept(Visitor visitor);
}
"具体元素"
public class Engineer extends Staff {
public Engineer(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public int getCodeLines(){
return new Random().nextInt(10*10000);
}
}
"具体元素"
public class Manager extends Staff {
private int products;
public Manager(String name) {
super(name);
products = new Random().nextInt(10);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public int getProducts(){
return products;
}
}
"对象结构-----元素被使用"
public class BusinessReport {
private List<Staff> mStaffs = new LinkedList<Staff>();
public BusinessReport() {
mStaffs.add(new Manager("王经理"));
mStaffs.add(new Engineer("工程师-Shanwm"));
mStaffs.add(new Engineer("工程师-Canwm"));
mStaffs.add(new Engineer("工程师-Xii"));
mStaffs.add(new Engineer("工程师-Jiuan"));
}
public void showReport(Visitor visitor){
System.out.println("--------------------------");
for(Staff staff:mStaffs){
staff.accept(visitor);
}
}
}
"调用 对象结构,"
public class Client {
public static void main(String[] args) {
BusinessReport report = new BusinessReport();
report.showReport(new CEOVisitor());
report.showReport(new CTOVisitor());
}
}
---------"输出"
--------------------------
经理:王经理,KPI:4,新产品量:7
工程师:工程师-Shanwm,KPI:0
工程师:工程师-Canwm,KPI:8
工程师:工程师-Xii,KPI:9
工程师:工程师-Jiuan,KPI:9
--------------------------
经理:王经理,新产品量:7
工程师:工程师-Shanwm,代码行数:24767
工程师:工程师-Canwm,代码行数:98568
工程师:工程师-Xii,代码行数:5828
工程师:工程师-Jiuan,代码行数:42639
**10/ 中介者模式 **
租房各位都有过的经历吧!在这个过程中中介结构扮演着很重要的角色,它在这里起到一个中间者的作用,给我们和房主互相传递信息。在外面软件的世界里同样需要这样一个中间者。在我们的系统中有时候会存在着对象与对象之间存在着很强、复杂的关联关系,如果让他们之间有直接的联系的话,必定会导致整个系统变得非常复杂,而且可扩展性很差!在前面我们就知道如果两个类之间没有不必彼此通信,我们就不应该让他们有直接的关联关系,如果实在是需要通信的话,我们可以通过第三者来转发他们的请求。同样,这里我们利用中介者来解决这个问题。
所谓中介者模式就是用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。在中介者模式中,中介对象用来封装对象之间的关系,各个对象可以不需要知道具体的信息通过中介者对象就可以实现相互通信。它减少了对象之间的互相关系,提供了系统可复用性,简化了系统的结构。
在中介者模式中,各个对象不需要互相知道了解,他们只需要知道中介者对象即可,但是中介者对象就必须要知道所有的对象和他们之间的关联关系,正是因为这样就导致了中介者对象的结构过于复杂,承担了过多的职责,同时它也是整个系统的核心所在,它有问题将会导致整个系统的问题。所以如果在系统的设计过程中如果出现“多对多”的复杂关系群时,千万别急着使用中介者模式,而是要仔细思考是不是您设计的系统存在问题。
//抽象中介者
public abstract class Mediator {
public abstract void change(Colleague colleague);
}
//子配件
public abstract class Colleague {
protected Mediator mMediator;
public Colleague(Mediator mediator) {
mMediator = mediator;
}
}
public class CPU extends Colleague {
private String dataVideo,dataSound;
public CPU(Mediator mediator) {
super(mediator);
}
public String getDataSound() {
return dataSound;
}
public String getDataVideo() {
return dataVideo;
}
public void decodeData(String data){
String[] tmp = data.split(",");
//
dataVideo = tmp[0];
dataSound = tmp[1];
mMediator.change(this);
}
}
public class CDDevice extends Colleague {
private String data;
public CDDevice(Mediator mediator) {
super(mediator);
}
public String read(){
return data;
}
public void load(){
data = "视频数据[马克思主义基本原理.mp4],音频数据[张召忠说.mp3]";
mMediator.change(this);
}
}
public class GraphicsCard extends Colleague {
public GraphicsCard(Mediator mediator) {
super(mediator);
}
public void vedioPlay(String data){
System.out.println("播放视频:"+data);
}
}
public class SoundCard extends Colleague {
public SoundCard(Mediator mediator) {
super(mediator);
}
public void soundPlay(String data){
System.out.println("播放音频:"+data);
}
}
public class MainBoard extends Mediator {
private CDDevice mCDDevice;
private CPU mCPU;
private SoundCard mSoundCard;
private GraphicsCard mGraphicsCard;
@Override
public void change(Colleague colleague) {
if(colleague==mCDDevice){
handleCD((CDDevice)colleague);
}else if(colleague==mCPU){
handleCD((CPU)colleague);
}
}
private void handleCD(CDDevice cdDevice) {
mCPU.decodeData(cdDevice.read());
}
private void handleCD(CPU cpu) {
mSoundCard.soundPlay(cpu.getDataSound());
mGraphicsCard.vedioPlay(cpu.getDataVideo());
}
public void setCDDevice(CDDevice CDDevice) {
mCDDevice = CDDevice;
}
public void setCPU(CPU CPU) {
mCPU = CPU;
}
public void setSoundCard(SoundCard soundCard) {
mSoundCard = soundCard;
}
public void setGraphicsCard(GraphicsCard graphicsCard) {
mGraphicsCard = graphicsCard;
}
}
public class Client {
public static void main(String[] args) {
MainBoard mainBoard = new MainBoard();
CDDevice cdDevice = new CDDevice(mainBoard);
GraphicsCard graphicsCard = new GraphicsCard(mainBoard);
SoundCard soundCard = new SoundCard(mainBoard);
CPU cpu = new CPU(mainBoard);
mainBoard.setCDDevice(cdDevice);
mainBoard.setCPU(cpu);
mainBoard.setGraphicsCard(graphicsCard);
mainBoard.setSoundCard(soundCard);
cdDevice.load();
}
}
----"输出"
播放音频:音频数据[张召忠说.mp3]
播放视频:视频数据[马克思主义基本原理.mp4]
三: 结构型模式
**1/ 代理模式 **
代理模式就是给一个对象提供一个代理,并由代理对象控制对原对象的引用。它使得客户不能直接与真正的目标对象通信。代理对象是目标对象的代表,其他需要与这个目标对象打交道的操作都是和这个代理对象在交涉。
代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了的作用和保护了目标对象的,同时也在一定程度上面减少了系统的耦合度。
public class ProxySubject extends Subject {
private RealSubject realSubject;
//代理模式/委托模式
//引用真实的对象
public void setRealSubject(RealSubject realSubject){
this.realSubject = realSubject;
}
@Override
public void visit() {
realSubject.visit();
}
}
public abstract class Subject {
public abstract void visit();
}
public class RealSubject extends Subject {
@Override
public void visit() {
System.out.println("Real Subject");
}
}
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxySubject proxySubject = new ProxySubject();
proxySubject.setRealSubject(realSubject);
proxySubject.visit();
}
}
动态代理
public class DynamicProxy implements InvocationHandler {
private Object obj;
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(obj,args);
return result;
}
public ILawsuit getRealProxy(ClassLoader loader) {
return (ILawsuit)Proxy.newProxyInstance(loader,new Class[]{ILawsuit.class},this);
}
}
public interface ILawsuit {
void sumit();
void finish();
}
public class XiaoMing implements ILawsuit {
@Override
public void sumit() {
System.out.println("XiaoMing: sumit");
}
@Override
public void finish() {
System.out.println("XiaoMing: finish");
}
}
public class Client {
public static void main(String[] args) {
XiaoMing xiaoMing = new XiaoMing();
DynamicProxy proxy = new DynamicProxy(xiaoMing);
ClassLoader loader = xiaoMing.getClass().getClassLoader();
ILawsuit lawyer = proxy.getRealProxy(loader);
lawyer.sumit();
lawyer.finish();
}
}
**2/ 组合模式 **
组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。它定义了如何将容器对象和叶子对象进行递归组合,使得客户在使用的过程中无须进行区分,可以对他们进行一致的处理。在使用组合模式中需要注意一点也是组合模式最关键的地方:叶子对象和组合对象实现相同的接口。这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。
虽然组合模式能够清晰地定义分层次的复杂对象,也使得增加新构件也更容易,但是这样就导致了系统的设计变得更加抽象,如果系统的业务规则比较复杂的话,使用组合模式就有一定的挑战了。
//抽象根节点
public abstract class Component {
String name;
public Component(String name) {
= name;
}
public abstract void doSomethings();
}
public class Composite extends Component {
private List<Component> mList = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void doSomethings() {
if(null!=mList){
System.out.println("--------"+name);
System.out.println("枝干节点:"+name);
for (Component c:mList){
c.doSomethings();
}
System.out.println("--------"+name);
}
}
public void add(Component c){
mList.add(c);
}
public void remove(Component c){
mList.remove(c);
}
public void getChild(int index){
mList.get(index);
}
}
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void doSomethings() {
System.out.println("叶子构件:"+name);
}
}
public class Client {
public static void main(String[] args) {
Composite root = new Composite("root");
Composite child = new Composite("child");
Composite branch1 = new Composite("branch1");
Composite branch2 = new Composite("branch2");
Composite branch3 = new Composite("branch3");
branch1.add(new Leaf("leaf1"));
branch2.add(new Leaf("leaf2"));
child.add(new Leaf("leaf3"));
child.add(new Leaf("leaf4"));
branch3.add(child);
root.add(branch1);
root.add(branch2);
root.add(branch3);
root.doSomethings();
}
}
**3/ 适配器模式 **
在我们的应用程序中我们可能需要将两个不同接口的类来进行通信,在不修改这两个的前提下我们可能会需要某个中间件来完成这个衔接的过程。这个中间件就是适配器。所谓适配器模式就是将一个类的接口,转换成客户期望的另一个接口。它可以让原本两个不兼容的接口能够无缝完成对接。
作为中间件的适配器将目标类和适配者解耦,增加了类的透明性和可复用性。
public interface Volt5 {
public int getVolt5();
}
public class Volt220 {
public int getVolt220(){
return 220;
}
}
public class Volt5Adapter implements Volt5 {
Volt220 mVolt220;
public Volt5Adapter(Volt220 volt220) {
mVolt220 = volt220;
}
public int getVolt220(){
return mVolt220.getVolt220();
}
@Override
public int getVolt5() {
return 5;
}
}
public class Test {
public static void main(String[] args) {
Volt220 volt220 = new Volt220();
Volt5Adapter adapter = new Volt5Adapter(volt220);
System.out.println(adapter.getVolt5()); // "220V的电压转5V"
System.out.println(adapter.getVolt220());
}
}
**4/ 装饰模式 **
我们可以通过继承和组合的方式来给一个对象添加行为,虽然使用继承能够很好拥有父类的行为,但是它存在几个缺陷:一、对象之间的关系复杂的话,系统变得复杂不利于维护。二、容易产生“类爆炸”现象。三、是静态的。在这里我们可以通过使用装饰者模式来解决这个问题。
装饰者模式,动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。虽然装饰者模式能够动态将责任附加到对象上,但是他会产生许多的细小对象,增加了系统的复杂度。
public abstract class Person {
public abstract void dress();
}
public class Boy extends Person {
@Override
public void dress() {
System.out.println("穿着内衣内裤");
}
}
public abstract class PersonCloth extends Person {
protected Person mPerson;
public PersonCloth(Person person) {
mPerson = person;
}
@Override
public void dress() {
mPerson.dress();
}
}
public class CheapCloth extends PersonCloth {
public CheapCloth(Person person) {
super(person);
}
private void dressShorts(){
System.out.println("便宜的短裤+短袖");
}
@Override
public void dress() {
//也可以在这里写,看需求
super.dress();
dressShorts();
}
}
public class ExpensiveCloth extends PersonCloth {
public ExpensiveCloth(Person person) {
super(person);
}
@Override
public void dress() {
super.dress();
dressShorts();
dressJean();
dressLeather();
}
private void dressShorts(){
System.out.println("贵的短袖");
}
private void dressJean(){
System.out.println("贵的牛仔裤");
}
private void dressLeather(){
System.out.println("贵的皮衣");
}
}
public class Test {
public static void main(String[] args) {
Boy boy = new Boy();
PersonCloth expensiveCloth = new ExpensiveCloth(boy);
expensiveCloth.dress();
System.out.println("-----");
PersonCloth cheapCloth = new CheapCloth(boy);
cheapCloth.dress();
}
}
-------输出
穿着内衣内裤
贵的短袖
贵的牛仔裤
贵的皮衣
-----
穿着内衣内裤
便宜的短裤+短袖
5/亨元模式
在一个系统中对象会使得内存占用过多,特别是那些大量重复的对象,这就是对系统资源的极大浪费。享元模式对对象的重用提供了一种解决方案,它使用共享技术对相同或者相似对象实现重用。享元模式就是运行共享技术有效地支持大量细粒度对象的复用。系统使用少量对象,而且这些都比较相似,状态变化小,可以实现对象的多次复用。这里有一点要注意:享元模式要求能够共享的对象必须是细粒度对象。享元模式通过共享技术使得系统中的对象个数大大减少了,同时享元模式使用了内部状态和外部状态,同时外部状态相对独立,不会影响到内部状态,所以享元模式能够使得享元对象在不同的环境下被共享。同时正是分为了内部状态和外部状态,享元模式会使得系统变得更加复杂,同时也会导致读取外部状态所消耗的时间过长。
public interface Ticket {
void showTicketInfo(String bunk); //bunk 铺位
}
public class TrainTicket implements Ticket {
String from;
String to;
String bunk;
int price;
public TrainTicket(String from, String to) {
this.from = from;
this.to = to;
}
@Override
public void showTicketInfo(String bunk) {
this.bunk = bunk;
setPrice();
System.out.println("购票信息:"+toString());
}
//票价不固定, 查询系统可得
private void setPrice(){
// System.out.println("此时的价位 已更新");
price = new Random().nextInt(300);
}
@Override
public String toString() {
return "TrainTicket{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", bunk='" + bunk + '\'' +
", price=" + price +
'}';
}
}
public class TicketFactory {
static Map<String,Ticket> ticketMap = new ConcurrentHashMap<>();
public static Ticket getTicket(String from, String to){
String key = from + "-" +to;
if(ticketMap.containsKey(key)){
System.out.println("使用缓存==>"+key);
return ticketMap.get(key);
}else {
System.out.println("创建新对象==>"+key);
TrainTicket trainTicket = new TrainTicket(from,to);
ticketMap.put(key,trainTicket);
return trainTicket;
}
}
}
public class Client {
public static void main(String[] args) {
Ticket t1 = TicketFactory.getTicket("北京","青岛");
t1.showTicketInfo("上铺");
Ticket t2 = TicketFactory.getTicket("北京","青岛");
t2.showTicketInfo("下铺");
Ticket t3 = TicketFactory.getTicket("北京","青岛");
t3.showTicketInfo("上铺");
Ticket t4 = TicketFactory.getTicket("北京","广州");
t4.showTicketInfo("上铺");
Ticket t5 = TicketFactory.getTicket("北京","广州");
t5.showTicketInfo("下铺");
}
}
----------------输出
创建新对象==>北京-青岛
购票信息:TrainTicket{from='北京', to='青岛', bunk='上铺', price=54}
使用缓存==>北京-青岛
购票信息:TrainTicket{from='北京', to='青岛', bunk='下铺', price=290}
使用缓存==>北京-青岛
购票信息:TrainTicket{from='北京', to='青岛', bunk='上铺', price=200}
创建新对象==>北京-广州
购票信息:TrainTicket{from='北京', to='广州', bunk='上铺', price=276}
使用缓存==>北京-广州
购票信息:TrainTicket{from='北京', to='广州', bunk='下铺', price=144}
6/外观模式
我们都知道类与类之间的耦合越低,那么可复用性就越好,如果两个类不必彼此通信,那么就不要让这两个类发生直接的相互关系,如果需要调用里面的方法,可以通过第三者来转发调用。外观模式非常好的诠释了这段话。外观模式提供了一个统一的接口,用来访问子系统中的一群接口。它让一个应用程序中子系统间的相互依赖关系减少到了最少,它给子系统提供了一个简单、单一的屏障,客户通过这个屏障来与子系统进行通信。通过使用外观模式,使得客户对子系统的引用变得简单了,实现了客户与子系统之间的松耦合。但是它违背了“开闭原则”,因为增加新的子系统可能需要修改外观类或客户端的源代码。
public interface Camera {
void open();
void takePhoto();
void close();
}
public class CameraImpl implements Camera {
@Override
public void open() {
System.out.println("打开相机");
}
@Override
public void takePhoto() {
System.out.println("拍照");
}
@Override
public void close() {
System.out.println("关闭相机");
}
}
public interface Phone {
void dail();
void hangup();//挂断
}
public class PhoneImpl implements Phone {
@Override
public void dail() {
System.out.println("打电话");
}
@Override
public void hangup() {
System.out.println("挂断电话");
}
}
public class MobilePhone {
private Phone mPhone = new PhoneImpl();
private Camera mCamera = new CameraImpl();
public void dail(){
mPhone.dail();
}
public void videoChat(){
System.out.println("-->视频聊天接通ing");
mCamera.open();
mPhone.dail();
}
public void hangup(){
mPhone.hangup();
}
public void takePhoto(){
mCamera.takePhoto();
}
public void closeCamera(){
mCamera.close();
}
}
public class PhoneTest {
public static void main(String[] args) {
MobilePhone mobilePhone = new MobilePhone();
//mobilePhone.dail();
mobilePhone.takePhoto();
mobilePhone.videoChat();
}
}
**7/桥接模式 **
如果说某个系统能够从多个角度来进行分类,且每一种分类都可能会变化,那么我们需要做的就是讲这多个角度分离出来,使得他们能独立变化,减少他们之间的耦合,这个分离过程就使用了桥接模式。所谓桥接模式就是讲抽象部分和实现部分隔离开来,使得他们能够独立变化。
桥接模式将继承关系转化成关联关系,封装了变化,完成了解耦,减少了系统中类的数量,也减少了代码量。
public abstract class CoffeeAdditives {
//由子类决定加什么
public abstract String addSth();
}
public abstract class Coffee {
protected CoffeeAdditives additives;
public Coffee(CoffeeAdditives additives) {
this.additives = additives;
}
public abstract void makeCoffee();
}
public class LargeCoffee extends Coffee {
public LargeCoffee(CoffeeAdditives additives) {
super(additives);
}
@Override
public void makeCoffee() {
System.out.println("大杯的+"+additives.addSth()+"+咖啡");
}
}
public class SmallCoffee extends Coffee {
public SmallCoffee(CoffeeAdditives additives) {
super(additives);
}
@Override
public void makeCoffee() {
System.out.println("小杯的+"+additives.addSth()+"+咖啡");
}
}
public class Sugar extends CoffeeAdditives {
@Override
public String addSth() {
return "加糖的";
}
}
public class Ordinary extends CoffeeAdditives {
@Override
public String addSth() {
return "原味的";
}
}
public class Main {
public static void main(String[] args) {
// 材料
Ordinary ordinary = new Ordinary();
Sugar sugar = new Sugar();
// 各种口味的咖啡
//大杯
LargeCoffee largeCoffeeOrdinary = new LargeCoffee(ordinary);
largeCoffeeOrdinary.makeCoffee();
LargeCoffee largeCoffeeSugar = new LargeCoffee(sugar);
largeCoffeeSugar.makeCoffee();
//小杯
SmallCoffee smallCoffeeOrdinary = new SmallCoffee(ordinary);
smallCoffeeOrdinary.makeCoffee();
SmallCoffee smallCoffeeSugar = new SmallCoffee(sugar);
smallCoffeeSugar.makeCoffee();
}
}
//输出
//大杯的+原味的+咖啡
//大杯的+加糖的+咖啡
//小杯的+原味的+咖啡
//小杯的+加糖的+咖啡
·