设计原则(7种)
这七大原则应该成为你在日常开发中的理论指导,只要你或多或少的遵循这七大设计原则,那么写出的代码就不会太烂,慢慢的你会发现你竟然理解了那些吊炸天的设计模式意图及设计思路。
软件的面向对象开发一般提倡遵循SOLID原则,这个单词就是我们这里前5个原则的首字母缩写。
单一职责原则
-
这个原则顾名思义,就是一个类应该只负责一个职责,术语叫:仅有一个引起其变化的原因。
-
简单点说:一个类中应该是一组相关性很高的函数及数据的封装。
-
看起来简单,但是做起来就难了,这可能是六大原则中最难以熟练掌握的一个原则了,它高度依赖程序员的自身素质及业务场景。
例如两个男性码农能为是否应该将一个函数写进某个类里面吵一天,最后谁也没有说服谁,最后他两成了好基友!
-
其实单一职责不仅在类中遵循,在方法中也应该遵循,下面是几个判断是否违反原则的参考:
-
一个方法中if else等条件语句特别多。
-
一个类中依赖了很多其他的类。
-
一个类根据参数的值执行不同的任务。
-
接口隔离原则
- 客户端**不应该依赖它不需要的接口**。一个类对另一个类的依赖应该建立在最小的接口上。
- 其实这个原则是很容易理解的,就是让调用者依赖的接口尽可能的小。例如人类分男人和女人,男人和女人都要吃饭,但是只有女人每个月来大姨妈,那么如果你设计一个接口里面除了吃饭还有来大姨妈同时给男人和女人用就不合适了。这你让男人情何以堪,万一有个菜鸟程序员抽风了,直接给把来大姨妈的方法实现了,那后果就。。。
- 上面的例子就违反了接口隔离原则,正确的做法是申明两个接口,使接口保持最小。
依赖倒置原则
-
依赖倒置原则(Dependence Inversion Principle)是**程序要依赖于抽象接口,不要依赖于具体实现**。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
-
依赖关系传递的三种方式
-
接口传递
-
构造方法传递
-
setter方法传递
-
开闭原则(ocp)
-
开闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
-
那么是不是就一定不能修改原来的类的,当然不是了,我们都是成年人了,要清楚的认识到,这个世界不是非黑即白的。当我们发现原来的类已经烂到家了,当然在有条件的情况下及时重构,避免系统加速腐败。
-
违反此原则的参考:增加需求时总是需要不断修改对应的代码
里氏替换原则
* 里氏代换原则(Liskov Substitution Principle, LSP):所有引用基类(父类)的地方必须能透明地使用其子类的对象。
* 简单点说,一个软件系统中所有用到一个类的地方都替换成其子类,系统应该仍然可以正常工作。
迪米特法则
* 迪米特法则(Law of Demeter, LoD):一个软件实体应当尽可能少地与其他实体发生相互作用。
* 一个类应该对自己需要调用的类知道得最少,类的内部如何实现、如何复杂都与调用者或者依赖者没关系,调用者或者依赖者只需要知道他需要的方法即可,其他的我一概不关心。
合成复用原则
* 合成复用原则(Composite Reuse Principle,CRP)又叫组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)。它要求在软件复用时,要尽量**<u>先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现</u>**。
* 如果要使用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成的,两者都是开闭原则的具体实现规范。
创建者模式(4种)
单例模式
通过单例模式的方法创建的类在当前进程中只有一个实例
-
饿汉式(2种):简单粗暴,提前准备好了对象,直接拿来就吃。
优点:线程安全 ,反应快。 缺点:可能会造成内存资源浪费。
- 静态变量方式
public class Singleton { //私有构造方法 private Singleton(){} //本类中创建私有的静态的成员对象 private final static Singleton instance = new Singleton(); //给外部提供一个公共的访问方法 public static Singleton getInstance(){ return instance; } }
- 静态代码块方式
public class Singleton { //私有构造方法 private Singleton(){} //声明Singleton类型的私有的静态的变量 private static Singleton instance; //在静态代码块中赋值 static { instance = new Singleton(); } //给外部提供一个公共的访问方法 public static Singleton getInstance(){ return instance; } }
-
懒汉式:很懒,什么时候需要的时候它才会去创建对象
优点:资源利用率高。 缺的:首次加载慢,线程不安全,需要加synchonized锁或静态内部类的方式实现。
-
静态变量方式(线程不安全)
public class Singleton { //私有构造方法 private Singleton(){} //声明Singleton类型的私有的静态的变量 private static Singleton instance; //给外部提供一个公共的访问方法 public static Singleton getInstance(){ //判断instance是否是null,是null就创建对象,否则直接返回 if(instance == null){ //创建instance对象 instance = new Singleton(); } //返回instance return instance; } }
-
同步方法(线程安全)
public class Singleton { //私有构造方法 private Singleton(){} //声明Singleton类型的私有的静态的变量 private static Singleton instance; //给外部提供一个公共的访问方法 public static synchronized Singleton getInstance(){ //判断instance是否是null,是null就创建对象,否则直接返回 if(instance == null){ //创建instance对象 instance = new Singleton(); } //返回instance return instance; } }
-
同步代码块(线程不安全)
public class Singleton { //私有构造方法 private Singleton(){} //声明Singleton类型的私有的静态的变量 private static Singleton instance; //给外部提供一个公共的访问方法 public static Singleton getInstance(){ //判断instance是否是null,是null就创建对象,否则直接返回 if(instance == null){ synchronized (Singleton.class){ //创建instance对象 instance = new Singleton(); } } //返回instance return instance; } }
-
-
双重检查锁
public class Singleton { //私有构造方法 private Singleton(){} //声明Singleton类型的变量 volatile避免指令重排 private static volatile Singleton instance; //给外部提供一个公共的访问方法 public static synchronized Singleton getInstance(){ //判断instance是否是null,是null就创建对象,否则直接返回 if(instance == null){ synchronized (Singleton.class){ if(instance == null){ //创建instance对象 instance = new Singleton(); } } } //返回instance return instance; } }
-
静态内部类
public class Singleton { //私有构造方法 private Singleton(){} //私有的静态内部类 private static class SingletonHolder{ //创建instance对象 private static final Singleton INSTANCE = new Singleton(); } //给外部提供一个公共的访问方法 public static Singleton getInstance(){ //返回instance return SingletonHolder.INSTANCE; } }
-
枚举方式
public enum Singleton { INSTANCE }
总结:
**一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式**
工厂模式
研究一下三种工厂模式,其均为创建型模式,即讨论的是如何创建一个类的对象的问题。就是以各种高逼格的方式最终将一个类的对象new出来,一点也不神秘。如果你发现需要一个类的对象而你又不会这些装X神器,那你就直接new好啦,爱谁谁。。。不过你也就逃脱不永远是个小白的命运啦,过几年混不下去了就只能去卖奶茶,什么?你不想那么快就去卖奶茶,那就好好学习这些装X神器!
-
简单工厂模式
-
根据传递的参数不同返回参数值对应的实例对象。
- 简单工厂模式又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由工厂决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
-
实现方式
简单工厂模式的实质是由工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例
/**
* 咖啡类
*/
public abstract class Coffee {
//获取咖啡名字
public abstract String getName();
public void addSugar(){
System.out.println("加糖");
}
public void addMilk(){
System.out.println("加奶");
}
}
/**
* 拿铁咖啡类
*/
public class LatteCoffee extends Coffee{
@Override
public String getName() {
return "我是拿铁咖啡";
}
}
/**
* 美式咖啡类
*/
public class AmericanCoffee extends Coffee{
@Override
public String getName() {
return "我是美式咖啡";
}
}
/**
* 简单工厂 注:此方法违背了开闭原则
*/
public class SimpleCoffeeFactory {
//获取咖啡 静态工厂需用static修饰此方法即可
public Coffee createCoffee(String type) {
Coffee coffee;
if("latte".equals(type)){
coffee = new LatteCoffee();
} else if("american".equals(type)){
coffee = new AmericanCoffee();
} else{
throw new RuntimeException("没有您要的这种咖啡");
}
return coffee;
}
}
/**
* 咖啡店
*/
public class CoffeeShop {
//点咖啡
public Coffee orderCoffee(String type){
//获取简单工厂对象
SimpleCoffeeFactory simpleCoffeeFactory = new SimpleCoffeeFactory();
//通过工厂对象获取咖啡对象
Coffee coffee = simpleCoffeeFactory.createCoffee(type);
//加糖
coffee.addSugar();
//加奶
coffee.addMilk();
//返回咖啡
return coffee;
}
}
/**
* 咖啡测试类
*/
public class CoffeeTest {
public static void main(String[] args) {
//咖啡店对象
CoffeeShop coffeeShop = new CoffeeShop();
//获取咖啡
Coffee latte = coffeeShop.orderCoffee("latte");
//获取咖啡名
String name = latte.getName();
//打印
System.out.println(name);
}
}
- 工厂方法模式
- 工厂方法模式(FACTORY METHOD)是一种常用的类创建型设计模式,此模式的核心是提取其中善变的部分为独立的抽象类,通过子类以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;具体产品
- 工厂方法模式为每一种产品生成一个对应的工厂,从而替换掉简单工厂方法模式中那个静态工厂方法。
使用场景:
- 你不想直接new这个类的对象,怕以后这个类改变的时候你需要回来改代码,而此时依赖这个类的地方已经到处都是了。
- 这个类的对象构建过程非常复杂,你不愿意将这么复杂的构建过程一遍又一遍的写在需要用到此对象的地方。
- 这个类的对象在构建过程中依赖了很多其他的类,而你无法在调用的地方提供。
/**
* 咖啡类
*/
public abstract class Coffee {
//获取咖啡名字
public abstract String getName();
public void addSugar(){
System.out.println("加糖");
}
public void addMilk(){
System.out.println("加奶");
}
}
/**
* 拿铁咖啡类
*/
public class LatteCoffee extends Coffee {
@Override
public String getName() {
return "我是拿铁咖啡";
}
}
/**
* 美式咖啡类
*/
public class AmericanCoffee extends Coffee {
@Override
public String getName() {
return "我是美式咖啡";
}
}
/**
* 咖啡工厂抽象接口
*/
public interface CoffeeFactory {
//创建咖啡
Coffee createCoffee();
}
/**
* 拿铁咖啡工厂
*/
public class LatteCoffeeFactory implements CoffeeFactory{
//创建拿铁咖啡
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
}
/**
* 美式咖啡工厂
*/
public class AmericanCoffeeFactory implements CoffeeFactory{
//创建美式咖啡
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}
}
/**
* 咖啡店
*/
public class CoffeeShop {
//声明咖啡工厂
private CoffeeFactory coffeeFactory;
//给工厂赋值
public void setCoffeeFactory(CoffeeFactory coffeeFactory){
this.coffeeFactory=coffeeFactory;
}
//点咖啡
public Coffee orderCoffee(){
//获取咖啡
Coffee coffee = coffeeFactory.createCoffee();
//加糖
coffee.addSugar();
//加奶
coffee.addMilk();
//返回咖啡
return coffee;
}
}
/**
* 咖啡测试类
*/
public class CoffeeTest {
public static void main(String[] args) {
//咖啡店对象
CoffeeShop coffeeShop = new CoffeeShop();
//拿铁咖啡工厂对象
LatteCoffeeFactory latteCoffeeFactory = new LatteCoffeeFactory();
//给咖啡店属性赋值
coffeeShop.setCoffeeFactory(latteCoffeeFactory);
//获取咖啡
Coffee latte = coffeeShop.orderCoffee();
//获取咖啡名
String name = latte.getName();
//打印
System.out.println(name);
}
}
- 抽象工厂模式 注:抽象工厂模式在工厂方法模式上进行了扩展,比如工厂模式有蛋糕工厂,水果工厂,可以生产蛋糕和水果,而抽象工厂蛋糕工厂下不仅可以生产蛋糕,还可以生产蛋挞,巧克力,面包等,水果工厂也不近只生产水果,还可以生产果盘,礼盒等商品。
抽象工厂模式(Abstract Factory Pattern)隶属于设计模式中的创建型模式,用于产品族的构建。抽象工厂是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂是指当有多个抽象角色时使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象。
工厂模式中的每一个形态都是针对一定问题的解决方案,工厂方法针对的是多个产品系列结构;而抽象工厂模式针对的是多个产品族结构,一个产品族内有多个产品系列。
/**
* 咖啡类
*/
public abstract class Coffee {
//获取咖啡名字
public abstract String getName();
public void addSugar(){
System.out.println("咖啡加糖");
}
public void addMilk(){
System.out.println("咖啡加奶");
}
}
/**
* 甜点类
*/
public abstract class Dessert {
public abstract String getName();
public void addSugar(){
System.out.println("甜点加糖");
}
}
/**
* 拿铁咖啡类
*/
public class LatteCoffee extends Coffee {
@Override
public String getName() {
return "我是拿铁咖啡";
}
}
/**
* 拿铁甜点类
*/
public class LatteDessert extends Dessert{
@Override
public String getName() {
return "拿铁甜点";
}
}
/**
* 美式咖啡类
*/
public class AmericanCoffee extends Coffee {
@Override
public String getName() {
return "我是美式咖啡";
}
}
/**
* 美式甜点
*/
public class AmericanDessert extends Dessert{
@Override
public String getName() {
return "美式甜点";
}
}
/**
* 咖啡店工厂
*/
public interface CoffeeShopFactory {
//创建咖啡
Coffee createCoffee();
//创建甜点
Dessert createDessert();
}
/**
* 拿铁工厂
*/
public class LatteFactory implements CoffeeShopFactory{
//创建拿铁咖啡
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
//创建拿铁甜点
@Override
public Dessert createDessert() {
return new LatteDessert();
}
}
/**
* 美式工厂
*/
public class AmericanFactory implements CoffeeShopFactory{
//创建美式咖啡
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}
//创建美式甜点
@Override
public Dessert createDessert() {
return new AmericanDessert();
}
}
/**
* 咖啡店
*/
public class CoffeeShop {
//声明咖啡工厂
private CoffeeShopFactory coffeeShopFactory;
//给工厂赋值
public void setCoffeeShopFactory(CoffeeShopFactory coffeeShopFactory){
this.coffeeShopFactory=coffeeShopFactory;
}
//点咖啡
public Coffee orderCoffee(){
//获取咖啡对象
Coffee coffee = coffeeShopFactory.createCoffee();
//加糖
coffee.addSugar();
//加奶
coffee.addMilk();
//返回咖啡
return coffee;
}
//点甜点
public Dessert orderDessert(){
//获取甜点对象
Dessert dessert = coffeeShopFactory.createDessert();
//加糖
dessert.addSugar();
//返回甜点
return dessert;
}
}
/**
* 咖啡测试类
*/
public class CoffeeShopTest {
public static void main(String[] args) {
//获取咖啡店
CoffeeShop coffeeShop = new CoffeeShop();
//美式工厂
/*AmericanFactory factory = new AmericanFactory();*/
//拿铁工厂
LatteFactory factory = new LatteFactory();
//给咖啡店工厂属性赋值
coffeeShop.setCoffeeShopFactory(factory);
//从咖啡店获取咖啡
Coffee coffee = coffeeShop.orderCoffee();
//获取咖啡名
String coffeeName = coffee.getName();
//从咖啡店获取甜点
Dessert dessert = coffeeShop.orderDessert();
//获取甜点名
String dessertName = dessert.getName();
//打印
System.out.println(coffeeName);
System.out.println(dessertName);
}
}
原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
- 浅克隆
浅克隆只可以克隆一级对象,如果对象里包含对象就需要使用深度克隆啦
/**
* 学生类 使用浅克隆需要实现Cloneable接口,重写clone方法
*/
public class Students implements Cloneable{
@Override
protected Students clone() throws CloneNotSupportedException {
return (Students) super.clone();
}
}
/**
* 测试类 结果false
*/
public class TestMain {
public static void main(String[] args) throws CloneNotSupportedException {
Students students = new Students();
Students clone = students.clone();
System.out.println(students==clone);
}
}
- 深克隆
- 通过重写clone类实现
/**
* 学生类 使用深克隆需要实现Cloneable接口,重写clone方法
*/
public class Students implements Cloneable {
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Students students;
students =(Students) super.clone();
students.teacher=teacher.clone();
return students;
}
}
/**
* 老师类
*/
public class Teacher implements Cloneable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Teacher clone() throws CloneNotSupportedException {
return (Teacher)super.clone();
}
}
/**
* 测试类
*/
public class TestMain {
public static void main(String[] args) throws IOException, ClassNotFoundException, CloneNotSupportedException {
Students students = new Students();
Teacher teacher = new Teacher();
teacher.setName("张三");
students.setTeacher(teacher);
Students students1 = (Students)students.clone();
System.out.println(students.getTeacher().hashCode());
System.out.println(students1.getTeacher().hashCode());
}
}
- 深克隆通过反序列化方式实现,可以实现多级克隆。注意:多级别对象需要实现Serializable接口
/**
* 学生类
*/
public class Students implements Serializable {
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}
/**
* 老师类
*/
public class Teacher implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 测试类
* 打印结果 张三 李四
*/
public class TestMain {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteArrayOutputStream = null;
ObjectOutputStream objectOutputStream = null;
ByteArrayInputStream byteArrayInputStream = null;
ObjectInputStream objectInputStream = null;
Students students = new Students();
Teacher teacher = new Teacher();
teacher.setName("张三");
students.setTeacher(teacher);
//通过反序列化的方式进行深克隆
byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(students);
objectOutputStream.close();
byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
objectInputStream = new ObjectInputStream(byteArrayInputStream);
Students students1 = (Students) objectInputStream.readObject();
objectInputStream.close();
students1.getTeacher().setName("李四");
System.out.println(students.getTeacher().getName());
System.out.println(students1.getTeacher().getName());
//关闭流
objectInputStream.close();
byteArrayInputStream.close();
objectOutputStream.close();
byteArrayOutputStream.close();
}
}
建造者模式
建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
- 第一种实现方式
/**
* 自行车类 (表示被构造的复杂对象)
*/
public class Bike {
//车架
private String frame;
//车座
private String seat;
public String getFrame() {
return frame;
}
public void setFrame(String frame) {
this.frame = frame;
}
public String getSeat() {
return seat;
}
public void setSeat(String seat) {
this.seat = seat;
}
}
/**
* 抽象构建器 (为创建一个产品对象的各个部件指定抽象接口)
*/
public abstract class Builder {
//声明自行车类并赋值
protected Bike biKe= new Bike();
//构建车架方法
public abstract void buildFrame();
//构建车座方法
public abstract void buildSeat();
//组装自行车
abstract Bike CreateBike();
}
/**
* 具体的构建者,用来构建摩拜单车、(实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。)
*/
public class MobileBuilder extends Builder{
@Override
public void buildFrame() {
biKe.setFrame("碳纤维车架");
}
@Override
public void buildSeat() {
biKe.setSeat("镁合金车轮");
}
//组装自行车
@Override
public Bike CreateBike(){
return biKe;
}
}
/**
* 具体的构建者,用来构建ofo单车。(实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。)
*/
public class OfoBuilder extends Builder{
@Override
public void buildFrame() {
biKe.setFrame("不锈钢车架");
}
@Override
public void buildSeat() {
biKe.setSeat("铝合金车轮");
}
//组装自行车
@Override
public Bike CreateBike(){
return biKe;
}
}
/**
* 指挥者类 (构造一个使用Builder接口的对象。)
*/
public class Director {
private Builder builder;
public Director(Builder builder){
this.builder=builder;
}
//组装自行车
public Bike Construct(){
builder.buildFrame();
builder.buildSeat();
return builder.CreateBike();
}
}
/**
* 测试类
* 打印结果 碳纤维车架 镁合金车轮
*/
public class TestMain {
public static void main(String[] args) {
MobileBuilder builder = new MobileBuilder();
Director director = new Director(builder);
Bike construct = director.Construct();
System.out.println(construct.getFrame());
System.out.println(construct.getSeat());
}
}
- 第二种实现方式
/**
* 电脑类
*/
public class Computer {
//cpu
private String cpu;
//处理器
private String processor;
//主板
private String mainboard;
//电源
private String powerSupply;
private Computer(Builder builder){
this.cpu = builder.cpu;
this.processor = builder.processor;
this.mainboard = builder.mainboard;
this.powerSupply = builder.powerSupply;
}
//内部类
public static final class Builder{
//cpu
private String cpu;
//处理器
private String processor;
//主板
private String mainboard;
//电源
private String powerSupply;
public Builder cpu(String cpu){
this.cpu = cpu;
return this;
}
public Builder processor(String processor){
this.processor = processor;
return this;
}
public Builder mainboard(String mainboard){
this.mainboard = mainboard;
return this;
}
public Builder powerSupply(String powerSupply){
this.powerSupply = powerSupply;
return this;
}
public Computer build(){
return new Computer(this);
}
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", processor='" + processor + '\'' +
", mainboard='" + mainboard + '\'' +
", powerSupply='" + powerSupply + '\'' +
'}';
}
}
/**
* 测试类
* 打印结果 Computer{cpu='Intel酷睿', processor='Intel酷睿i5 10400F(散片)', mainboard='微星B460M-MORTAR 迫击炮', * powerSupply='长城 HOPE-5000DS电源 '}
*/
public class TestMain {
public static void main(String[] args) {
Computer computer = new Computer.Builder()
.cpu("Intel酷睿")
.processor("Intel酷睿i5 10400F(散片)")
.mainboard("微星B460M-MORTAR 迫击炮")
.powerSupply("长城 HOPE-5000DS电源 ")
.build();
System.out.println(computer);
}
}
结构型模式(7种)
适配器模式
适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表 示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同 工作
以生活中充电器的例子来讲解适配器,充电器本身相当于Adapter,220V交流电 相当于src (即被适配者),我们的目dst(即 目标)是5V直流电
- 类适配器模式
/*
* 被适配类 电压220伏
*/
public class Voltage220V {
//电压
private int voltage;
//获取配适配器电压
public int getVoltage(){
voltage = 220;
return voltage;
}
}
/**
* 转换电压的接口类
*/
public interface IVoltage5V {
//转换5v
int output5V();
}
/**
* 电压适配器类
*/
public class VoltageAdapter extends Voltage220V implements IVoltage5V{
//实现转换5v方法
@Override
public int output5V() {
//获取220伏电压
int voltage = getVoltage();
//转换为5伏后返回
return voltage/44;
}
}
/**
* 手机类
*/
public class Phone {
//充电
public void charging(VoltageAdapter voltageAdapter){
//根据适配器获取当前电压
int i = voltageAdapter.output5V();
//等于5伏可以充电,否则电压过高,转换失败
if(i==5){
System.out.println("可以为手机充电!");
}else{
System.out.println("电压过大,你不能充电");
}
}
/**
* 测试类
*/
public class TestMain {
public static void main(String[] args) {
//手机类对象
Phone phone = new Phone();
//调用充电方法
phone.charging(new VoltageAdapter());
}
}
- 对象适配器模式
/*
* 被适配类 电压220伏
*/
public class Voltage220V {
//电压
private int voltage;
//获取配适配器电压
public int getVoltage(){
voltage = 220;
return voltage;
}
}
/**
* 转换电压的接口类
*/
public interface IVoltage5V {
//转换5v
int output5V();
}
/**
* 电压适配器类
*/
public class VoltageAdapter implements IVoltage5V{
//这里使用组合模式实现,也可以用聚合实现
private Voltage220V voltage220V = new Voltage220V();
//实现转换5v方法
@Override
public int output5V() {
//获取220伏电压
int voltage = voltage220V.getVoltage();
//转换为5伏后返回
return voltage/44;
}
}
/**
* 手机类
*/
public class Phone {
//充电
public void charging(VoltageAdapter voltageAdapter){
//根据适配器获取当前电压
int i = voltageAdapter.output5V();
//小于等于5伏可以充电,否则电压过高,转换失败
if(i<=5){
System.out.println("可以为手机充电!");
}else{
System.out.println("电压过大,你不能充电");
}
}
}
/**
* 测试类
*/
public class TestMain {
public static void main(String[] args) {
//手机类对象
Phone phone = new Phone();
//调用充电方法
phone.charging(new VoltageAdapter());
}
}
- 接口适配器模式
/**
* 被适配接口 有一些方法用不到
*/
public interface Interface {
void m1();
void m2();
void m3();
void m4();
void m5();
}
/**
* 抽象适配器,空实现接口方法
*/
public abstract class AbsAdapter implements Interface {
@Override
public void m1() {
}
@Override
public void m2() {
}
@Override
public void m3() {
}
@Override
public void m4() {
}
@Override
public void m5() {
}
}
/**
* 测试类
*/
public class TestMain {
public static void main(String[] args) {
//适配器对象,用那个方法重写那个方法
AbsAdapter adapter = new AbsAdapter() {
@Override
public void m1() {
System.out.println("我使用了m1方法");
}
};
//调用重写后的方法
adapter.m1();
}
}
桥接模式
桥接模式(Bridge模式)是指:将实现与抽象放在两个不同的类层次中,使两个层 次可以独立改变。
桥接模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同 的类承担不同的职责。它的主要特点是把抽象(Abstraction)与行为实现 (Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能 扩展。
现在对不同手机类型(折叠手机, 直板手机)的不同品牌(Vivo品牌,小米品牌)实现操作编程
/**
* 品牌
*/
public interface Brand {
void call();
}
/**
* Vivo品牌
*/
public class Vivo implements Brand{
@Override
public void call() {
System.out.println("我用vivo手机打电话");
}
}
/**
* 小米品牌
*/
public class Xiaomi implements Brand{
@Override
public void call() {
System.out.println("我用小米手机打电话");
}
}
/**
* 手机抽象类 ,聚合了品牌接口
*/
public abstract class Phone {
private Brand brand;
public Phone(Brand brand) {
this.brand = brand;
}
public void call(){
brand.call();
}
}
/**
* 折叠手机
*/
public class FoldedPhone extends Phone{
public FoldedPhone(Brand brand) {
super(brand);
}
@Override
public void call() {
super.call();
System.out.println("我是折叠手机");
}
}
/**
* 直板手机
*/
public class UpRightPhone extends Phone{
public UpRightPhone(Brand brand) {
super(brand);
}
@Override
public void call() {
super.call();
System.out.println("我是直板手机");
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
Phone phone1 = new FoldedPhone(new Xiaomi());
phone1.call();
System.out.println("--------------------------");
Phone phone2 = new UpRightPhone(new Vivo());
phone2.call();
}
}
装饰者模式
动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更 有弹性,装饰者模式也体现了开闭原则(ocp)。
这里有点绕,研究好久发现“动态的将新功能附加到对象上”其实就是把新的对象通过套娃的方式套起来,然后再通过递归的方式一个一个获取。
星巴克咖啡订单项目(咖啡馆):
- 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式 咖啡)、Decaf(无因咖啡)
- 调料:Milk、Soy(豆浆)、Chocolate
- 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
- 使用OO的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖 啡+调料组合。
/**
* 饮料
*/
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() {
System.out.println("调用一次");
System.out.println(super.getClass().getSimpleName());
return super.getPrice();
}
}
/**
* 意大利咖啡
*/
public class Espresso extends Coffee{
public Espresso(){
setDes("意大利咖啡");
setPrice(6.0f);
}
}
/**
* 美式咖啡LongBlack
*/
public class LongBlack extends Coffee{
public LongBlack(){
setDes("longBlack");
setPrice(5.0f);
}
}
/**
* 美式咖啡ShortBlack
*/
public class ShortBlack extends Coffee{
public ShortBlack(){
setDes("shortBlack");
setPrice(4.0f);
}
}
/**
* 装饰者类
*/
public class Decorator extends Drink{
private final Drink drink;
public Decorator(Drink drink){
this.drink=drink;
}
@Override
public float cost() {
System.out.println("调用一次");
System.out.println(super.getClass().getSimpleName()+" === "+drink.getClass().getSimpleName());
return super.getPrice() + drink.cost();
}
@Override
public String getDes() {
return super.getDes()+" "+super.getPrice() +" && "+drink.getDes();
}
}
/**
* 具体的装饰类,这里是巧克力调味品
*/
public class Chocolate extends Decorator{
public Chocolate(Drink obj) {
super(obj);
setDes("巧克力");
setPrice(3.0f);
}
}
/**
* 具体的装饰类,这里是牛奶调味品
*/
public class Milk extends Decorator{
public Milk(Drink obj) {
super(obj);
setDes("牛奶");
setPrice(2.0f);
}
}
/**
* 具体的装饰类,这里是豆浆调味品
*/
public class Soy extends Decorator{
public Soy(Drink obj) {
super(obj);
setDes("豆浆");
setPrice(1.5f);
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
Drink order = new LongBlack();
order = new Milk(order);
order = new Soy(order);
System.out.println(order.cost());
}
}
组合模式
组合模式(Composite Pattern),又叫部分整体模式,它创建了对象组的树形结 构,将对象组合成树状结构以表示“整体-部分”的层次关系。
组合模式使得用户对单个对象和组合对象的访问具有一致性,即:组合能让客 户以一致的方式处理个别对象以及组合对象
应用实例要求 编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组 成,一个学校有多个学院,一个学院有多个系。
/**
* 组合类,可以是抽象类,接口等任意类型
*/
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();
}
protected abstract void print();
public OrganizationComponent(String name, String des) {
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;
}
}
/**
* 大学
*/
public class University extends OrganizationComponent {
List<OrganizationComponent> list= new ArrayList<OrganizationComponent>();
public University(String name, String des) {
super(name, des);
}
@Override
protected void add(OrganizationComponent organizationComponent) {
list.add(organizationComponent);
}
@Override
protected void remove(OrganizationComponent organizationComponent) {
list.remove(organizationComponent);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println("-------------"+getName()+"----------------");
for (OrganizationComponent component : list) {
component.print();
}
}
}
/**
* 学院
*/
public class College extends OrganizationComponent{
List<OrganizationComponent> list= new ArrayList<OrganizationComponent>();
public College(String name, String des) {
super(name, des);
}
@Override
protected void add(OrganizationComponent organizationComponent) {
list.add(organizationComponent);
}
@Override
protected void remove(OrganizationComponent organizationComponent) {
list.remove(organizationComponent);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println("-------------"+getName()+"----------------");
for (OrganizationComponent component : list) {
component.print();
}
}
}
/**
* 专业
*/
public class Department extends OrganizationComponent{
public Department(String name, String des) {
super(name, des);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println("-------------"+getName()+"----------------");
}
}
/**
* 客户端测试
*/
public class Client {
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("网络工程","网络工程很好学"));
//学院添加专业
infoEngineerCollege.add(new Department("信息工程","信息工程不错"));
infoEngineerCollege.add(new Department("通信工程","通信工程不错"));
//大学添加学院
university.add(computerCollege);
//大学添加学院
university.add(infoEngineerCollege);
//打印
university.print();
}
}
外观模式
- 外观模式(Facade),也叫“过程模式:外观模式为子系统中的一组接口提供 一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加 容易使用
- 外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端 只需跟这个接口发生调用,而无需关心这个子系统的内部细节
/**
* DVD播放器
*/
public class DVDPlayer {
private static DVDPlayer dvdPlayer = new DVDPlayer();
public static DVDPlayer getInstanc(){
return dvdPlayer;
}
public void on(){
System.out.println("DVD 打开");
}
public void off(){
System.out.println("DVD 关闭");
}
}
/**
* 爆米花机
*/
public class Popcorn {
private static Popcorn popcorn = new Popcorn();
public static Popcorn getInstanc(){
return popcorn;
}
public void on(){
System.out.println("爆米花机 打开");
}
public void off(){
System.out.println("爆米花机 关闭");
}
}
/**
* 外观类。注:外观模式一般调用类比较多的时候使用,如果调用比较简单就没必要使用了。
* 当前因为举例设置了两个子系统对象,一般情况两个对象没必要使用外观模式的。
*/
public class HomeTheaterFacade {
//各个子系统对象
private DVDPlayer dvdPlayer;
private Popcorn popcorn;
//通过单例模式初始化系统对象
public HomeTheaterFacade() {
this.dvdPlayer = DVDPlayer.getInstanc();
this.popcorn = Popcorn.getInstanc();
}
//准备开始
public void ready(){
dvdPlayer.on();
popcorn.on();
}
//关闭
public void end(){
dvdPlayer.off();
popcorn.off();
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
//初始化外观类
HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();
//调用打开方法
homeTheaterFacade.ready();
System.out.println("-----------------------------");
//调用关闭方法
homeTheaterFacade.end();
}
}
享元模式
- 享元模式(Flyweight Pattern) 也叫 蝇量模式: 运 用共享技术有效地支持大量细粒度的对象
- 常用于系统底层开发,解决系统的性能问题。像 数据库连接池,里面都是创建好的连接对象,在 这些连接对象中有我们需要的则直接拿来用,避 免重新创建,如果没有我们需要的,则创建一个
- 享元模式能够解决重复对象的内存浪费的问题, 当系统中有大量相似对象,需要缓冲池时。不需 总是创建新对象,可以从缓冲池里拿。这样可以 降低系统内存,同时提高效率
- 享元模式经典的应用场景就是池技术了,String常 量池、数据库连接池、缓冲池等等都是享元模式 的应用,享元模式是池技术的重要实现方式
总结:享元模式已有的对象可以共享,减少相同对象的创建。
/**
* 抽象网站
*/
public abstract class Website {
//使用
public abstract void use();
}
/**
* 具体的网站
*/
public class ConcreteWebsite extends Website{
private String type;
public ConcreteWebsite(String type) {
this.type = type;
}
@Override
public void use() {
System.out.println("这个网站是"+type);
}
}
/**
* 网站创建工厂
*/
public class WebsiteFactory {
private Map<String,Website> pool = new HashMap<String,Website>();
//根据type获取网站类别
public Website getWebsiteCategory(String type){
if(!pool.containsKey(type)){
//没有就添加一个
pool.put(type,new ConcreteWebsite(type));
}
//获取返回
return pool.get(type);
}
//获取网站类别数量
public int getWebsiteCount(){
return pool.size();
}
}
/**
* 客户端测试类
*/
public class Client {
public static void main(String[] args) {
//网站工厂
WebsiteFactory websiteFactory = new WebsiteFactory();
//创建网站对象
Website website1 = websiteFactory.getWebsiteCategory("新闻");
Website website2 = websiteFactory.getWebsiteCategory("新浪");
Website website3 = websiteFactory.getWebsiteCategory("新浪");
//使用网站
website1.use();
website2.use();
website3.use();
//获取对象数量,结果为2,相同对象不会重复创建
int websiteCount = websiteFactory.getWebsiteCount();
System.out.println(websiteCount);
}
}
代理模式
代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理 对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的 功能操作,即扩展目标对象的功能。
- 静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一 起实现相同的接口或者是继承相同父类,并且代理对象还需要聚合目标对象。
优点:在不修改目标对象的功能前提下, 能通过代理对象对目标功能扩展
缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类, 一旦接口增加方法,目标对象与代理对象都要维护
/**
* 教师接口
*/
public interface ITeacherService {
void teach();
}
/**
* 具体的老师实现类
*/
public class TeacherServiceImpl implements ITeacherService{
@Override
public void teach() {
System.out.println("老师授课中。。。。");
}
}
/**
* 代理类
*/
public class TeacherProxy implements ITeacherService{
//聚合目标类
private ITeacherService teacherService;
//构造方法给目标类赋值
public TeacherProxy(ITeacherService teacherService) {
this.teacherService = teacherService;
}
//代理方法
@Override
public void teach() {
//增强
System.out.println("上课了");
//目标方法
teacherService.teach();
//增强
System.out.println("放学啦");
}
}
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
//老师类
ITeacherService teacherService = new TeacherServiceImpl();
//老师代理类
TeacherProxy teacherProxy = new TeacherProxy(teacherService);
//代理方法
teacherProxy.teach();
}
}
- 动态代理
- 代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用动态代理
- 代理对象的生成,是利用JDK的API中newProxyInstance方法,动态的在内存中构建代理对象 3
- 动态代理也叫做:JDK代理、接口代理
/**
* 教师接口
*/
public interface ITeacherService {
void teach();
String hello(String name);
}
/**
* 具体的老师实现类
*/
public class TeacherServiceImpl implements ITeacherService{
@Override
public void teach() {
System.out.println("老师授课中。。。。");
}
@Override
public String hello(String name) {
System.out.println("hello,"+name);
return name;
}
}
/**
* 代理类
*/
public class TeacherProxy{
//聚合目标类
private Object teacherService;
//构造方法给目标类赋值
public TeacherProxy(Object teacherService) {
this.teacherService = teacherService;
}
//获取代理对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(teacherService.getClass().getClassLoader(),
teacherService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("上课了");
Object invoke = method.invoke(teacherService, args);
System.out.println("放学了");
return invoke;
}
});
}
}
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
//老师类
ITeacherService target = new TeacherServiceImpl();
//老师代理类
ITeacherService proxyInstance =(ITeacherService) new TeacherProxy(target).getProxyInstance();
//调用
proxyInstance.teach();
//String hello = proxyInstance.hello("豆豆");
//System.out.println(hello);
}
}
- Cglib代理(不依赖于接口)
- 静态代理和JDK代理模式都要求目标对象是实现一个接口,但是有时候目标对象只 是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现 代理-这就是Cglib代理
- Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功 能扩展, 有些书也将Cglib代理归属到动态代理。
- Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接 口.它广泛的被许多AOP的框架使用,例如Spring AOP,实现方法拦截
- 在AOP编程中如何选择代理模式: 1. 目标对象需要实现接口,用JDK代理 2. 目标对象不需要实现接口,用Cglib代理
- Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类
/**
* 具体的老师实现类
*/
public class Teacher{
@Override
public void teach() {
System.out.println("老师授课中。。。。");
}
}
/**
* 代理类
*/
public class TeacherProxy implements MethodInterceptor {
//聚合目标类
private Object target;
//构造方法给目标类赋值
public TeacherProxy(Object target) {
this.target = target;
}
public Object getProxyInstance(){
//工具类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(target.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建子类对象,即代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("上课啦");
Object invoke = method.invoke(target, objects);
System.out.println("放学啦");
return invoke;
}
}
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
//老师类
Teacher target = new Teacher();
//老师代理类
Teacher proxyInstance =(Teacher) new TeacherProxy(target).getProxyInstance();
//调用
proxyInstance.teach();
}
}
行为型模式(11种)
模板方法模式
模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern), 在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法 实现,但调用将以抽象类中定义的方式进行。 简单说,模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子 类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
- 普通模板方法
制作豆浆的流程 选材—>添加配料—>浸泡—>放到豆浆机打碎 ,通过添加不同的配料,可以制作出不同口味的豆浆
/**
* 豆浆制作过程抽象类
*/
public abstract class SoyaMilk {
//模板方法
public final void make(){
select();
addCondiments();
soak();
beat();
}
//选材
public void select(){
System.out.println("选择好黄豆");
}
//添加配料
public abstract void addCondiments();
//侵泡
public void soak(){
System.out.println("侵泡");
}
//打碎
public void beat(){
System.out.println("豆浆机研磨豆浆");
}
}
/**
* 制作红豆豆浆
*/
public class RedBeanSoyaMilk extends SoyaMilk{
@Override
public void addCondiments() {
System.out.println("添加上好的红豆");
}
}
/**
* 制作花生豆浆
*/
public class PeanutSoyaMilk extends SoyaMilk{
@Override
public void addCondiments() {
System.out.println("添加上好的花生");
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
SoyaMilk soyaMilk;
//制作花生豆浆
soyaMilk = new PeanutSoyaMilk();
soyaMilk.make();
System.out.println("------------------------");
//制作花生豆浆
soyaMilk = new RedBeanSoyaMilk();
soyaMilk.make();
}
}
-
模板方法-钩子方法
在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以 视情况要不要覆盖它,该方法称为“钩子”。
还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料
/**
* 豆浆制作过程抽象类
*/
public abstract class SoyaMilk {
//模板方法
public final void make(){
select();
if(customerWantCondiments()){
addCondiments();
}
soak();
beat();
}
//选材
public void select(){
System.out.println("选择好黄豆");
}
//添加配料
public abstract void addCondiments();
//侵泡
public void soak(){
System.out.println("侵泡");
}
//打碎
public void beat(){
System.out.println("豆浆机研磨豆浆");
}
//是否需要加配料
public boolean customerWantCondiments(){
return true;
}
}
/**
* 制作红豆豆浆
*/
public class RedBeanSoyaMilk extends SoyaMilk{
@Override
public void addCondiments() {
System.out.println("添加上好的红豆");
}
}
/**
* 制作花生豆浆
*/
public class PeanutSoyaMilk extends SoyaMilk{
@Override
public void addCondiments() {
System.out.println("添加上好的花生");
}
}
/**
* 纯豆浆
*/
public class PureSoyaMilk extends SoyaMilk{
//不需要配料
@Override
public void addCondiments() {
}
//不需要配料
@Override
public boolean customerWantCondiments() {
return false;
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
SoyaMilk soyaMilk;
//制作花生豆浆
soyaMilk = new PeanutSoyaMilk();
soyaMilk.make();
System.out.println("------------------------");
//制作花生豆浆
soyaMilk = new RedBeanSoyaMilk();
soyaMilk.make();
System.out.println("------------------------");
//制作纯豆浆
soyaMilk = new PureSoyaMilk();
soyaMilk.make();
}
}
命令模式
- 命令模式(Command Pattern):在软件设计中,我们经常需要 向某些对象发送请求,但是并不知道请求的接收者是谁,也不知 道被请求的操作是哪个, 我们只需在程序运行时指定具体的命令接收者即可,此时,可以 使用命令模式来进行设计
- 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让 对象之间的调用关系更加灵活,实现解耦。
- 在命名模式中,会将一个请求封装为一个对象,以便使用不同参 数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作
- 通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色: 将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将 军和士兵)。 Invoker是调用者(将军),Receiver是被调用者(士兵), MyCommand是命令,实现了Command接口,持有接收对象
例子:我们买了一套智能家电,有照明灯、风扇、冰箱、洗衣机,我们只要在手机上安装app就 可以控制对这些家电工作。这些智能家电来自不同的厂家,我们不想针对每一种家电都安装一个App,分别控制,我 们希望只要一个app就可以控制全部智能家电。 要实现一个app控制所有智能家电的需要,则每个智能家电厂家都要提供一个统一的接口 给app调用,这时 就可以考虑使用命令模式。 命令模式可将“动作的请求者”从“动作的执行者”对象中解耦出来。
下面我们用照明灯做例子进行实现,如果还想加入风扇,冰箱等家具只需添加相应的接收者,和不同的命令具体实现就可以完成对不同家具的操作。
/**
* 命令接口
*/
public interface Command {
//执行方法
void execute();
//撤销方法
void undo();
}
/**
* 灯光,命令接收者类
*/
public class LightReceiver {
//灯光打开方法
public void on(){
System.out.println("灯光打开了");
}
//灯光关闭方法
public void off(){
System.out.println("灯光关闭了");
}
}
/**
* 灯光命令的具体实现类 打开
*/
public class LightOnCommand implements Command{
//聚合灯光命令接收者对象
private LightReceiver lightReceiver;
//构造初始化
public LightOnCommand(LightReceiver lightReceiver){
//给灯光命令接收者对象赋值
this.lightReceiver=lightReceiver;
}
//实现接口中执行方法
@Override
public void execute() {
//命令执行者执行打开灯光的方法
lightReceiver.on();
}
//实现接口中撤销方法
@Override
public void undo() {
//命令执行者执行关闭灯光的方法
lightReceiver.off();
}
}
/**
* 灯光命令的具体实现类 关闭
*/
public class LightOffCommand implements Command{
//聚合灯光命令接收者对象
private LightReceiver lightReceiver;
//构造初始化
public LightOffCommand(LightReceiver lightReceiver){
//给灯光命令接收者对象赋值
this.lightReceiver = lightReceiver;
}
//实现接口中执行方法
@Override
public void execute() {
//命令执行者执行关闭灯光的方法
lightReceiver.off();
}
//实现接口中撤销方法
@Override
public void undo() {
//命令执行者执行打开灯光的方法
lightReceiver.on();
}
}
/**
* 空实现,做初始化用。
*/
public class NoCommand implements Command{
@Override
public void execute() {
}
@Override
public void undo() {
}
/**
* 遥控器
*/
public class RemoteController {
//开 命令集合
private Command[] onCommands;
//关 命令集合
private Command[] offCommands;
//撤销对象
private Command undoCommand;
//初始化
public RemoteController() {
//开 默认集合大小是5
onCommands = new Command[5];
//关 默认集合大小是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 onButtonWasPhshs( int no){
//调用打开对象的执行方法
onCommands[no].execute();
//把当前对象赋值给撤销对象
undoCommand=onCommands[no];
}
//关闭命令
public void offButtonWasPhshs( int no){
//调用关闭对象的执行方法
offCommands[no].execute();
//把当前对象赋值给撤销方法
undoCommand=offCommands[no];
}
//撤销命令
public void undoButtonWasPhshs( int no){
//撤销对象执行undo,撤销命令。
undoCommand.undo();
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
//创建灯光命令接收者对象
LightReceiver lightReceiver = new LightReceiver();
//灯光命令具体实现对象
LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
//遥控器
RemoteController remoteController = new RemoteController();
//给命令集合赋值
remoteController.setCommand(0 ,lightOnCommand,lightOffCommand);
//打开命令
remoteController.onButtonWasPhshs(0);
//关闭命令
remoteController.offButtonWasPhshs(0);
//撤销命令
remoteController.undoButtonWasPhshs(0);
}
}
访问者模式
- 访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作, 它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
- 主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题
- 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者 的接口
- 访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作 (这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以 选用访问者模式解决
例子:将观众分为男人和女人,对歌手进行测评,当看完某个歌手表演后,得到他们对 该歌手不同的评价(评价 有不同的种类,比如 成功、失败 等)
/**
* 抽象的访问者
*/
public abstract class Action {
//男人投票方法
public abstract void getManResult(Person man);
//女人投票方法
public abstract void getWomanResult(Person woman);
}
/**
* 具体的访问者 通过
*/
public class Success extends Action{
//男人投票方法
@Override
public void getManResult(Person man) {
System.out.println("男人举起通过的牌子");
}
//女人投票方法
@Override
public void getWomanResult(Person woman) {
System.out.println("女人举起通过的牌子");
}
}
/**
* 具体的访问者 失败
*/
public class Fail extends Action{
//男人投票方法
@Override
public void getManResult(Person man) {
System.out.println("男人举起失败的牌子");
}
//女人投票方法
@Override
public void getWomanResult(Person 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);
}
}
/**
* 接收访问者对象具体类
*/
public class Woman extends Person{
//接收访问者对象方法
@Override
public void accept(Action action) {
//通过访问者对象调用访问者方法
action.getWomanResult(this);
}
}
/**
* 结构体对象,聚合了接收访问者对象类
*/
public class ObjectStructure {
//接收访问者对象类集合
List<Person> persons = new LinkedList<>();
//添加接收访问者对象到接收访问者对象类集合
public void attach(Person p) {
persons.add(p);
}
//从接收访问者对象类集合中移除接收访问者
public void detach(Person p){
persons.remove(p);
}
//显示投票结果
public void display(Action action){
//遍历接收访问者对象类集合
for (Person person : persons) {
//调用接收访问者对象,并把访问者当成参数传递过去。
person.accept(action);
}
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
//结构体对象
ObjectStructure structure = new ObjectStructure();
//添加接收访问者对象到接收访问者对象类集合
structure.attach(new Man());
structure.attach(new Woman());
//具体的访问者 通过对象
Success success = new Success();
//具体的访问者 失败对象
Fail fail = new Fail();
//显示投票结果
structure.display(success);
structure.display(fail);
}
}
职责链模式
- 职责链模式(Chain of Responsibility Pattern), 又叫 责任链模式,为请求创建了一个接收者对象的链。这种模式对请求的 发送者和接收者进行解耦。
- 职责链模式通常每个接收者都包含对另一个接 收者的引用。如果一个对象不能处理该请求, 那么它会把相同的请求传给下一个接收者,依 此类推。
应用实例要求 :编写程序完成学校OA系统的采购审批项目:
需求 • 采购员采购教学器材 • 如果金额 小于等于5000, 由教学主任审批 • 如果金额 小于等于10000, 由院长审批 • 如果金额 小于等于30000, 由副校长审批 • 如果金额 超过30000以上,有校长审批
/**
* 购买请求类
*/
public class PurchaseRequest {
private int type = 0; //请求类型
private float price = 0.0f; //金额
private int id= 0; //id
public PurchaseRequest(int type, float price, int id) {
this.type = type;
this.price = price;
this.id = id;
}
public int getType() {
return type;
}
public float getPrice() {
return price;
}
public int getId() {
return id;
}
}
/**
* 抽象的审批者
*/
public abstract class Approver {
//通过聚合,可以调用下一个审批人
Approver approver;
String name; //审批人
public Approver(String name) {
this.name = name;
}
public void setApprover(Approver approver) {
this.approver = approver;
}
//处理请求
public abstract void processRequest(PurchaseRequest purchaseRequest);
}
/**
* 具体的审批者 教学主任
*/
public class DepartmentApprover extends Approver{
public DepartmentApprover(String name) {
super(name);
}
//教学主任处理类
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if(purchaseRequest.getPrice()<=5000){
System.out.println("请求编码id="+purchaseRequest.getId()+"被"+this.name+"调用");
}else{
//调用下一个下一级处理者
approver.processRequest(purchaseRequest);
}
}
}
/**
* 具体的审批者 院长
*/
public class CollegeApprover extends Approver{
public CollegeApprover(String name) {
super(name);
}
//院长处理类
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if(purchaseRequest.getPrice()>5000&&purchaseRequest.getPrice()<=10000){
System.out.println("请求编码id="+purchaseRequest.getId()+"被"+this.name+"调用");
}else{
//调用下一个下一级处理者
approver.processRequest(purchaseRequest);
}
}
}
/**
* 具体的审批者 副校长
*/
public class ViceSchoolMastereApprover extends Approver{
public ViceSchoolMastereApprover(String name) {
super(name);
}
//副校长处理类
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if(purchaseRequest.getPrice()>10000&&purchaseRequest.getPrice()<=30000){
System.out.println("请求编码id="+purchaseRequest.getId()+"被"+this.name+"调用");
}else{
//调用下一个下一级处理者
approver.processRequest(purchaseRequest);
}
}
}
/**
* 具体的审批者 校长
*/
public class SchoolMasterApprover extends Approver{
public SchoolMasterApprover(String name) {
super(name);
}
//校长处理类
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if(purchaseRequest.getPrice()>30000){
System.out.println("请求编码id="+purchaseRequest.getId()+"被"+this.name+"调用");
}else{
//调用下一个下一级处理者
approver.processRequest(purchaseRequest);
}
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
//初始化请求类
PurchaseRequest purchaseRequest = new PurchaseRequest(1,31000,1);
//初始化教学主任类
DepartmentApprover departmentApprover = new DepartmentApprover("教学主任审批");
//初始化院长类
CollegeApprover collegeApprover = new CollegeApprover("院长审批");
//初始化副校长类
ViceSchoolMastereApprover viceSchoolMastereApprover = new ViceSchoolMastereApprover("副校长审批");
//初始化校长类
SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("校长审批");
//给教学主任指定院长为下一级审批人
departmentApprover.setApprover(collegeApprover);
//给院长指定副校长为下一级审批人
collegeApprover.setApprover(viceSchoolMastereApprover);
//给副校长指定校长为下一级审批人
viceSchoolMastereApprover.setApprover(schoolMasterApprover);
//给校长指定教学主任为下一级审批人
schoolMasterApprover.setApprover(departmentApprover);
//处理请求
departmentApprover.processRequest(purchaseRequest);
}
}
策略模式
- 策略模式(Strategy Pattern)中,定义算法族,分别封装起来,让他们之间可以 互相替换,此模式让算法的变化独立于使用算法的客户
- 这算法体现了几个设计原则,第一、把变化的代码从不变的代码中分离出来; 第二、针对接口编程而不是具体类(定义了策略接口);第三、多用组合/聚合, 少用继承(客户通过组合方式使用策略)
编写鸭子项目,具体要求如下: 有各种鸭子(比如 野鸭、北京鸭、水鸭等, 鸭子有各种行为,比如 叫、飞行等) 显示鸭子的信息
// 策略接口 飞翔接口
public interface FlyBehavior {
//飞行
public void fly();
}
//有飞翔能力
public class GoodFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("鸭子会飞翔~~");
}
}
//无飞翔能力
public class NoFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("鸭子不会飞翔~~");
}
}
/**
* 鸭子抽象类
*/
public abstract class Duck {
FlyBehavior flyBehavior;
public Duck() {
}
public abstract void display();
/* public void quack(){
System.out.println("鸭子嘎嘎叫~~");
}*/
public void swim(){
System.out.println("鸭子会游泳~~");
}
public void fly(){
flyBehavior.fly();
}
}
//北京鸭子
public class PekingDuck extends Duck{
public PekingDuck() {
flyBehavior = new NoFlyBehavior();
}
@Override
public void display() {
System.out.println("北京鸭");
}
}
//玩具鸭子
public class ToDuck extends Duck{
public ToDuck() {
flyBehavior = new NoFlyBehavior();
}
@Override
public void display() {
System.out.println("玩具鸭");
}
}
//野鸭子
public class WildDuck extends Duck{
public WildDuck() {
flyBehavior = new GoodFlyBehavior();
}
@Override
public void display() {
System.out.println("野鸭");
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
//北京鸭子对象
Duck duck = new PekingDuck();
duck.display();
duck.fly();
//玩具鸭子对象
duck = new ToDuck();
duck.display();
duck.fly();
//野鸭子对象
duck = new WildDuck();
duck.display();
duck.fly();
}
}