一、什么是设计模式
- 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因
二、为什么学习设计模式
- 它是很多人很多年以来的经验智慧的总结,教你怎样更高效的来玩耍代码,使原来单一的代码模式变得有趣,漂亮。他是使编程艺术化的入门。
三、常见的面向对象设计原则
1、迪米特法则,又称最少知道原则(Demeter Principle)
- 最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
从依赖者的角度来说,只依赖应该依赖的对象。
从被依赖者的角度说,只暴露应该暴露的方法。降低耦合
假设类A实现了某个功能,类B需要调用类A的去执行这个功能,那么类A应该只暴露一个函数给类B,这个函数表示是实现这个功能的函数,而不是让类A把实现这个功能的所有细分的函数暴露给B。
2、里氏代换原则
- 基类和子类之间的关系。子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
关于里氏替换原则的例子,最有名的是“正方形不是长方形”。当然,生活中也有很多类似的例子,例如,企鹅、鸵鸟和几维鸟从生物学的角度来划分,它们属于鸟类;但从类的继承关系来看,由于它们不能继承“鸟”会飞的功能,所以它们不能定义成“鸟”的子类。同样,由于“气球鱼”不会游泳,所以不能定义成“鱼”的子类;“玩具炮”炸不了敌人,所以不能定义成“炮”的子类等。
3、依赖倒转原则(Dependence Inversion Principle)
它降低了客户与实现模块之间的耦合。
由于在软件设计中,细节具有多变性,而抽象层则相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。这里的抽象指的是接口或者抽象类,而细节是指具体的实现类。
使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成。
比如常见的参数里传的是父类,而不是具体类,比如一个售卖功能里面的参数是商店,商店有可能是北京商店,也可能是上海商店,所以这个号参数要使用商店这个类而不是具体的某个商店
4、接口隔离原则(Interface Segregation Principle)
- 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。以下这里例子一眼就能对比出接口隔离的好处了
public interface UserService {
public void login(String username, String password);
public void register(String email, String username, String password);
public void logError(String msg);
public void sendEmail(String email);
}
5、开闭原则(Open Close Principle)
- 开闭原则的意思是:对扩展开放,对修改关闭。
在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
6、单一原则(Composite Reuse Principle)
- 一个类单一职责,防止耦合
四、设计模式分类
如下图所示:
创建型模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用新的运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
public class ShapeFactory {
//普通工厂模式,不符合开闭原则
public Shape getShape(String shapeType){
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
抽象工厂更符合开-闭原则,降低耦合,但抽象工厂模式很难支持新种类产品的变化。类复杂。实际应用中使用简单工厂多点
public class Singleton {
//饿汉模式,简单,线程安全,效率高,但一开始就加载了,容易产生垃圾
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
public class User {
private final String firstName; // 必传参数
private final String lastName; // 必传参数
private final int age; // 可选参数
private final String phone; // 可选参数
private final String address; // 可选参数
private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
public static class UserBuilder {
private final String firstName;
private final String lastName;
private int age;
private String phone;
private String address;
public UserBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
public User build() {
return new User(this);
}
}
}
调用
new User.UserBuilder("王", "小二")
.age(20)
.phone("123456789")
.address("亚特兰蒂斯大陆")
.build();
- 原型模式 (Prototype Pattern):通过拷贝原型创建新的对象,当我们的类初始化需要消耗很多的资源时,就可以使用原型模式,因为我们的克隆不会执行构造方法,避免了初始化占有的时间和空间。
1、浅克隆:
对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。
对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组,某个类型的对象等,那么浅拷贝会进行引用传递,也就是只是该成员变量的引用值(内存地址)复制一份给新的对象,因为实际上两个对象的该成员变量都指向同一个实例,在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
//这里不实现Serializable接口也可以实现浅克隆
public class User implements Cloneable,Serializable{
private String name;
private Date birth;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* 实现克隆的方法
*/
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
//使用
Date date = new Date(1231231231231l);
User user = new User();
user.setName("波波烤鸭");
user.setAge(18);
user.setBirth(date);
System.out.println("----输出原型对象的属性------");
System.out.println(user);
System.out.println(user.getName());
System.out.println(user.getBirth());
// 克隆对象
User user1 =(User) user.clone();
// 修改原型对象中的属性
date.setTime(123231231231l);
System.out.println(user.getBirth());
// 修改参数
user1.setName("dpb");
System.out.println("-------克隆对象的属性-----");
System.out.println(user1);
System.out.println(user1.getName());
System.out.println(user1.getBirth());
//打印如下
----输出原型对象的属性-----
com.dpb.prototype.User@15db9742
波波烤鸭
Tue Jan 06 16:40:31 CST 2009 # 1
Tue Nov 27 14:53:51 CST 1973 # 2
-------克隆对象的属性-----
com.dpb.prototype.User@5c647e05
dpb
Tue Nov 27 14:53:51 CST 1973 # 和2的结果一样 说明两个对象的Date的引用是同一个
//虽然产生了两个完全不同的对象,但是被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象(比如Date)的引用都仍然指向原来的对象
深拷贝代码实例:
方式一:重写clone方法
public class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
//因为该类的属性,都是String,因此我们这里使用默认的clone完成即可.
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class DeepProtoType implements Serializable, Cloneable {
public String name;
public DeepCloneableTarget deepCloneableTarget;
public DeepProtoType() {
super();
}
//深拷贝 - 方式1 使用clone 方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
//完成对基本数据类型(属性)和String的克隆
deep = super.clone();
//对引用类型的属性,进行单独的处理。
DeepProtoType deepProtoType = (DeepProtoType) deep;
deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
return deep;
}
}
public class Client {
public static void main(String[] args) throws Exception{
DeepProtoType p = new DeepProtoType();
p.name="宋江";
p.deepCloneableTarget=new DeepCloneableTarget("大牛","小牛的");
//方式1 完成深拷贝
DeepProtoType p2=(DeepProtoType)p.clone();
System.out.println("p.name="+p.name+"p.deepCloneableTarget="+p.deepCloneableTarget.hashCode());
System.out.println("p2.name="+p2.name+"p.deepCloneableTarget="+p2.deepCloneableTarget.hashCode());
}
}
方式二:通过对象序列化来实现深拷贝(推荐使用)
DeepCloneableTarget类
public class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
//因为该类的属性,都是String,因此我们这里使用默认的clone完成即可.
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
DeepProtoType 类
public class DeepProtoType implements Serializable, Cloneable {
public String name;
public DeepCloneableTarget deepCloneableTarget;
public DeepProtoType() {
super();
}
//深拷贝 - 方式2 通过对象序列化实现(推荐使用)
public Object deepClone() {
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);//当前这个对象以对象流的方式输出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
DeepProtoType copyObj = (DeepProtoType) ois.readObject();
return copyObj;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
Client 测试用例
public class Client {
public static void main(String[] args) throws Exception {
DeepProtoType p = new DeepProtoType();
p.name = "宋江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛的");
//方式2 完成深拷贝
DeepProtoType p3=(DeepProtoType) p.deepClone();
System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
System.out.println("p3.name=" + p3.name + "p.deepCloneableTarget=" + p3.deepCloneableTarget.hashCode());
}
}
public class Computer {
//我们的电脑需要连接1:转按器才可以1:网
public void net(NetToUsb adapter) {
//.上网的具体实现, 找“个转接义
adapter.handleRequest();
}
public static void main(String[] args) {
Computer computer = new Computer(); //电脑
Adaptee adaptee = new Adaptee(); //网线
Adapter adapter = new Adapter(); //转按器
computer.net(adapter);*/
}
结构型模式
这些设计模式关注类和对象的组合。
//要被适配的类:网线
public class Adaptee {
public void request() {
System.out.println("连接网线上网");
}
}
//真正的适配器,需 要连接USB,连接网线~
public class Adapter extends Adaptee implements NetToUsb {
@Override
public void handleRequest() {
//上网的具体实现,找一个转接头
super.request();
}
}
//按1口转换器的抽象实现~
public interface NetToUsb {
//作1川:处理请求,网线=>usb
public void handleRequest();
}
public class Computer {
//我们的电脑需要连接1:转按器才可以1:网
public void net(NetToUsb adapter) {
//.上网的具体实现, 找“个转接义
adapter.handleRequest();
}
public static void main(String[] args) {
/* //电脑,适配器,网线~ 使用继承的方式
Computer computer = new Computer(); //电脑
Adaptee adaptee = new Adaptee(); //网线
Adapter adapter = new Adapter(); //转按器
computer.net(adapter);*/
System.out.println("++++++++++++++++++++++++++++++");
//电脑,适配器,网线~ 使用组合的方式
Computer computer = new Computer(); //电脑
Adaptee adaptee = new Adaptee(); //网线
Adapter2 adapter = new Adapter2(adaptee); //转按器
computer.net(adapter);
}
}
- [装饰器模式 (Decorator Pattern):允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。何时使用:在不想增加很多子类的情况下扩展类
第一代机器人只会跳舞,第二代机器人通过传入第一代机器人拥有了跳舞功能,然后增加唱歌功能呢。
public interface Robot {
void dance();
}
public class firstRobot implements Robot {
@Override
public void dance() {
System.out.println("dance: dance");
}
}
public class twoRobot implements Robot {
protected Robot rebot;
public ShapeDecorator(Robot rebot){
this.rebot = rebot;
}
public void dance(){
rebot.dance();
}
public void singing(){
}
}
-
桥接模式 (Bridge Pattern):两个维度独立变化,依赖方式实现抽象与实现分离:需要一个作为桥接的接口/抽象类,多个角度的实现类依赖注入到抽象类,使它们在抽象层建立一个关联关系
//品牌
public interface Brand {
void info();
}
public class Lenovo implements Brand {
@Override
public void info() {
System.out.print("联想");
}
}
public class Apple implements Brand {
@Override
public void info() {
System.out.print("苹果");
}
}
//抽象的电脑类型类
public abstract class Computer {
//组合,品牌~
protected Brand brand;
public Computer(Brand brand) {
this.brand = brand;
}
public void info() {
brand.info();//自带品牌
}
}
class Laptop extends Computer {
public Laptop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.print("笔记本");
}
}
- 外观模式 (Facade Pattern):在客户端和复杂系统之间再加一层,这一次将调用顺序、依赖关系等处理好。即封装底层实现,隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的高层接口
public class CPU {
public void startup(){
System.out.println("cpu startup!");
}
public void shutdown(){
System.out.println("cpu shutdown!");
}
}
public class Memory {
public void startup(){
System.out.println("memory startup!");
}
public void shutdown(){
System.out.println("memory shutdown!");
}
}
public class Disk {
public void startup(){
System.out.println("disk startup!");
}
public void shutdown(){
System.out.println("disk shutdown!");
}
}
public class Computer {
private CPU cpu;
private Memory memory;
private Disk disk;
public Computer(){
cpu = new CPU();
memory = new Memory();
disk = new Disk();
}
public void startup(){
System.out.println("start the computer!");
cpu.startup();
memory.startup();
disk.startup();
System.out.println("start computer finished!");
}
public void shutdown(){
System.out.println("begin to close the computer!");
cpu.shutdown();
memory.shutdown();
disk.shutdown();
System.out.println("computer closed!");
}
}
Computer computer = new Computer();
computer.startup();
computer.shutdown();
- 代理模式 (Proxy Pattern):为其他对象提供一种代理以控制对这个对象的访问:增加中间层(代理层),代理类与底层实现类实现共同接口,并创建底层实现类对象(底层实现类对象依赖注入代理类),以便向外界提供功能接口
public interface Image {
void display();
}
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName){
System.out.println("Loading " + fileName);
}
}
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
}
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 图像将从磁盘加载
image.display();
System.out.println("");
// 图像不需要从磁盘加载
image.display();
}
}
过滤器模式 (Filter、Criteria Pattern):使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来
https://www.runoob.com/design-pattern/filter-pattern.html组合模式 (Composite Pattern):用户对单个对象和组合对象的使用具有一致性的统一接口,何时使用: 1、您想表示对象的部分-整体层次结构(树形结构)。2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates;
//构造函数
public Employee(String name,String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}
public void add(Employee e) {
subordinates.add(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
public List<Employee> getSubordinates(){
return subordinates;
}
public String toString(){
return ("Employee :[ Name : "+ name
+", dept : "+ dept + ", salary :"
+ salary+" ]");
}
}
public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", 30000);
Employee headSales = new Employee("Robert","Head Sales", 20000);
Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
Employee clerk1 = new Employee("Laura","Marketing", 10000);
Employee clerk2 = new Employee("Bob","Marketing", 10000);
Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
CEO.add(headSales);
CEO.add(headMarketing);
headSales.add(salesExecutive1);
headSales.add(salesExecutive2);
headMarketing.add(clerk1);
headMarketing.add(clerk2);
//打印该组织的所有员工
System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
System.out.println(employee);
}
}
}
}
- 享元模式 (Flyweight Pattern):主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
public class Circle implements Shape {
private String color;
private int x;
private int y;
private int radius;
public Circle(String color){
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setRadius(int radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Circle: Draw() [Color : " + color
+", x : " + x +", y :" + y +", radius :" + radius);
}
}
public class ShapeFactory {
private static final HashMap<String, Shape> circleMap = new HashMap<>();
public static Shape getCircle(String color) {
Circle circle = (Circle)circleMap.get(color);
if(circle == null) {
circle = new Circle(color);
circleMap.put(color, circle);
System.out.println("Creating circle of color : " + color);
}
return circle;
}
}
//随机调用,有用过的会从hashmap中取出
public class FlyweightPatternDemo {
private static final String colors[] =
{ "Red", "Green", "Blue", "White", "Black" };
public static void main(String[] args) {
for(int i=0; i < 20; ++i) {
Circle circle =
(Circle)ShapeFactory.getCircle(getRandomColor());
circle.setX(getRandomX());
circle.setY(getRandomY());
circle.setRadius(100);
circle.draw();
}
}
private static String getRandomColor() {
return colors[(int)(Math.random()*colors.length)];
}
private static int getRandomX() {
return (int)(Math.random()*100 );
}
private static int getRandomY() {
return (int)(Math.random()*100);
}
}
行为型模式
这些设计模式特别关注对象之间的通信。
- 责任链模式(Chain of Responsibility Pattern):拦截的类都实现统一接口,每个接收者都包含对下一个接收者的引用。将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
//抽象处理者角色
abstract class Handler {
private Handler next;
public void setNext(Handler next) {
this.next = next;
}
public Handler getNext() {
return next;
}
//处理请求的方法
public abstract void handleRequest(String request);
}
//具体处理者角色1
class ConcreteHandler1 extends Handler {
public void handleRequest(String request) {
if (request.equals("one")) {
System.out.println("具体处理者1负责处理该请求!");
} else {
if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("没有人处理该请求!");
}
}
}
}
//具体处理者角色2
class ConcreteHandler2 extends Handler {
public void handleRequest(String request) {
if (request.equals("two")) {
System.out.println("具体处理者2负责处理该请求!");
} else {
if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("没有人处理该请求!");
}
}
}
}
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
//组装责任链
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setNext(handler2);
//提交请求
handler1.handleRequest("two");
}
}
/抽象目标
abstract class Subject {
protected List<Observer> observers = new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer) {
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer) {
observers.remove(observer);
}
public abstract void notifyObserver(); //通知观察者方法
}
//具体目标
class ConcreteSubject extends Subject {
public void notifyObserver() {
System.out.println("具体目标发生改变...");
System.out.println("--------------");
for (Object obs : observers) {
((Observer) obs).response();
}
}
}
//抽象观察者
interface Observer {
void response(); //反应
}
//具体观察者1
class ConcreteObserver1 implements Observer {
public void response() {
System.out.println("具体观察者1作出反应!");
}
}
//具体观察者1
class ConcreteObserver2 implements Observer {
public void response() {
System.out.println("具体观察者2作出反应!");
}
}
public class ObserverPattern {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
Observer obs1 = new ConcreteObserver1();
Observer obs2 = new ConcreteObserver2();
subject.add(obs1);
subject.add(obs2);
subject.notifyObserver();
}
}
- 模板模式(Template Pattern):将这些通用算法抽象出来,在一个抽象类中公开定义了执行它的方法的方式/模板。主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化游戏
initialize();
//开始游戏
startPlay();
//结束游戏
endPlay();
}
}
public class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
//不用命令模式,添加一个界面就要修改电视类和观看类
//电视机对象:提供了播放不同频道的方法
public class Television {
public void playCctv1() {
System.out.println("--CCTV1--");
}
public void playCctv2() {
System.out.println("--CCTV2--");
}
}
public class Watcher {
//持有一个
public Television tv;
public Watcher(Television tv) {
this.tv = tv;
}
public void playCctv1() {
tv.playCctv1();
}
public void playCctv2() {
tv.playCctv2();
}
}
Watcher watcher = new Watcher(new Television());
watcher.playCctv1();
watcher.playCctv2();
//使用命令模式
public abstract class Command {
//命令接收者:电视机
protected Television television;
public Command(Television television) {
this.television = television;
}
//命令执行
abstract void execute();
}
//播放cctv1的命令
public class CCTV1Command extends Command {
@Override
void execute() {
television.playCctv1();
}
}
//播放cctv2的命令
public class CCTV6Command extends Command {
@Override
void execute() {
television.playCctv2();
}
}
————————————————
historyCommand.add(command);
command.execute();
}
//遥控器返回命令
public class TeleController {
//播放记录
List<Command> historyCommand = new ArrayList<Command>();
//切换卫视
public void switchCommand(Command command) {
historyCommand.add(command);
command.execute();
}
public void back() {
if (historyCommand.isEmpty()) {
return;
}
int size = historyCommand.size();
int preIndex = size-2<=0?0:size-2;
//获取上一个播放某卫视的命令
Command preCommand = historyCommand.remove(preIndex);
preCommand.execute();
}
}
//创建一个电视机
Television tv = new Television();
//创建一个遥控器
TeleController teleController = new TeleController();
teleController.switchCommand(new CCTV1Command(tv));
teleController.switchCommand(new CCTV2Command(tv));
//模拟遥控器返回键
teleController.back();
teleController.back();
解释器模式(Interpreter Pattern):给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子
何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。迭代器模式(Iterator Pattern):集合中含有迭代器:分离了集合对象的遍历行为,抽象出一个迭代器类来负责,无须暴露该对象的内部表示
中介者模式(Mediator Pattern):对象与对象之间存在大量的关联关系,将对象之间的通信关联关系封装到一个中介类中单独处理,从而使其耦合松散,可以独立地改变它们之间的交互
策略模式(Strategy Pattern):策略对象依赖注入到context对象,context对象根据它的策略改变而改变它的相关行为(可通过调用内部的策略对象实现相应的具体策略行为)
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
public interface Strategy {
public int doOperation(int num1, int num2);
}
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
状态模式(State Pattern):状态对象依赖注入到context对象,context对象根据它的状态改变而改变它的相关行为(可通过调用内部的状态对象实现相应的具体行为)
备忘录模式(Memento Pattern):通过一个备忘录类专门存储对象状态。客户通过备忘录管理类管理备忘录类。
空对象模式(Null Object Pattern):创建一个未对该类做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方。不要为了屏蔽null而使用空对象,应保持用null,远比用非null的值来替代“无值”要好。(慎用)