java规范总结

  • 1. Java 常见的代码规范
    • 1.1. Java 自带的工具方法
      • 1.1.1 比较两个对象是否相等
      • 1.1.2 apache commons工具类库
        • 1.1.2.1 字符串判空
        • 1.1.2.3 重复拼接字符串
        • 1.1.2.4 格式化日期
        • 1.1.2.4 包装临时对象 (不是特别常用)
      • 1.1.3 common-beanutils 操作对象
      • 1.1.3.1 commons-io 文件流处理
      • 1.1.4 Google Guava 工具类库
        • 1.1.4.1 创建集合
    • 1.2 java 常见的代码规范
      • 1.2.1 使用Collection.isEmpty() 检测空
      • 1.2.2 初始化集合时尽量指定其大小
      • 1.2.3 若需频繁调用Collection.contains 方法则使用Set
      • 1.2.4 使用静态代码块实现赋值静态成员变量
      • 1.2.5 工具类中屏蔽构造函数
      • 1.2.6 删除未使用的局部变量、方法参数、私有方法、字段和多余的括号
      • 1.2.8 字符串转化使用String.valueOf(value) 代替 " " + value (需补充)
      • 1.2.9 避免使用BigDecimal(double)
  • 2. 设计模式
    • 2.1 装饰者模式订阅
      • 2.1.1 定义
      • 2.1.2职责
      • 2.1.3 装饰模式结构
      • 2.1.3 举一个简单的例子
      • 2.1.4 另一个很经典的一个场景
      • 2.1.5 需求抽象出来
      • 2.1.6 具体的类图
      • 2.1.7 装饰模式的优点
      • 2.1.8 缺点
    • 2.2 桥接者模式
      • 2.2.1 桥接模式概念
      • 2.2.2 结构图
      • 2.2.3 具体代码
      • 2.2.4 桥接模式的设计要点和适用性
      • 2.2.5 装饰模式和桥接模式的区别
    • 2.3 观察者模式
    • 2.4 责任链模式
    • 2.5 建造者模式
      • 2.5.1 概念
    • 2.6 组合这模式
      • 2.6.1 组合模式的概念
      • 2.6.2 组合模式结构
      • 2.6.3组合模式工作分析
    • 2.7 策略模式
    • 2.8 外观模式
      • 2.8.1 概念
    • 2.9 命令模式
      • 2.9.1 概念
      • 2.9.2 模式结构
      • 2.9.3 结构图
      • 2.9.3建议看这个代码
      • 2.9.4 命令模式的优缺点

感谢分享:

1. Java 常见的代码规范

1.1. Java 自带的工具方法

1.1.1 比较两个对象是否相等

当我们用equals比较两个对象是否相等的时候,还需要对左边的对象进行判空,不然可能会报空指针异常,我们可以用java.util包下Objects封装好的比较是否相等的方法:

 Objects.equals(strA, strB);

源码:

public static boolean equals(Object a, Object b) {  return (a == b) || (a != null && a.equals(b));
}

1.1.2 apache commons工具类库

apache commons是最强大的,也是使用最广泛的工具类库,里面的子库非常多,下面介绍几个最常用的

commons-lang,java.lang的增强版 建议使用commons-lang3,优化了一些api,原来的commons-lang已停止更新:

maven 的依赖:

org.apache.commons commons-lang3 3.12.0

1.1.2.1 字符串判空

传参CharSequence类型是String、StringBuilder、StringBuffer的父类,都可以直接下面方法判空,以下是源码:

public static boolean isEmpty(final CharSequence cs) {  return cs == null || cs.length() == 0;
}  public static boolean isNotEmpty(final CharSequence cs) {  return !isEmpty(cs);
}  // 判空的时候,会去除字符串中的空白字符,比如空格、换行、制表符
public static boolean isBlank(final CharSequence cs) {  final int strLen = length(cs);  if (strLen == 0) {  return true;  }  for (int i = 0; i < strLen; i++) {  if (!Character.isWhitespace(cs.charAt(i))) {  return false;  }  }  return true;
}  public static boolean isNotBlank(final CharSequence cs) {  return !isBlank(cs);
}

####1.1.2.2 首字母转大写 (这里可以查询源码看其他stringUtils 提供的其他源码,提供的新的特性)

String str = "yideng";
String capitalize = StringUtils.capitalize(str);
System.out.println(capitalize); // 输出Yideng

1.1.2.3 重复拼接字符串

String str = StringUtils.repeat("ab", 2);
System.out.println(str); // 输出abab

1.1.2.4 格式化日期

再也不用手写SimpleDateFormat格式化了

// Date类型转String类型
String date = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
System.out.println(date); // 输出 2021-05-01 01:01:01  // String类型转Date类型
Date date = DateUtils.parseDate("2021-05-01 01:01:01", "yyyy-MM-dd HH:mm:ss");  // 计算一个小时后的日期
Date date = DateUtils.addHours(new Date(), 1);

1.1.2.4 包装临时对象 (不是特别常用)

当一个方法需要返回两个及以上字段时,我们一般会封装成一个临时对象返回,现在有了Pair和Triple就不需要了

// 返回两个字段
ImmutablePair<Integer, String> pair = ImmutablePair.of(1, "yideng");
System.out.println(pair.getLeft() + "," + pair.getRight()); // 输出 1,yideng
// 返回三个字段
ImmutableTriple<Integer, String, Date> triple = ImmutableTriple.of(1, "yideng", new Date());
System.out.println(triple.getLeft() + "," + triple.getMiddle() + "," + triple.getRight()); // 输出 1,yideng,Wed Apr 07 23:30:00 CST 2021

1.1.3 commons-collections 集合工具类

封装了集合判空的方法,以下是源码:

public static boolean isEmpty(final Collection<?> coll) {  return coll == null || coll.isEmpty();
}  public static boolean isNotEmpty(final Collection<?> coll) {  return !isEmpty(coll);
}
// 两个集合取交集
Collection<String> collection = CollectionUtils.retainAll(listA, listB);
// 两个集合取并集
Collection<String> collection = CollectionUtils.union(listA, listB);
// 两个集合取差集
Collection<String> collection = CollectionUtils.subtract(listA, listB);

1.1.3 common-beanutils 操作对象

Maven依赖:

<dependency>  <groupId>commons-beanutils</groupId>  <artifactId>commons-beanutils</artifactId>  <version>1.9.4</version>
</dependency>
public class User {  private Integer id;  private String name;
}

设置对象属性

User user = new User();
BeanUtils.setProperty(user, "id", 1);
BeanUtils.setProperty(user, "name", "yideng");
System.out.println(BeanUtils.getProperty(user, "name")); // 输出 yideng
System.out.println(user); // 输出 {"id":1,"name":"yideng"}

对象和map互转

// 对象转map
Map<String, String> map = BeanUtils.describe(user);
System.out.println(map); // 输出 {"id":"1","name":"yideng"}
// map转对象
User newUser = new User();
BeanUtils.populate(newUser, map);
System.out.println(newUser); // 输出 {"id":1,"name":"yideng"}

1.1.3.1 commons-io 文件流处理

Maven依赖:

commons-io commons-io 2.8.0

文件处理

File file = new File("demo1.txt");
// 读取文件
List<String> lines = FileUtils.readLines(file, Charset.defaultCharset());
// 写入文件
FileUtils.writeLines(new File("demo2.txt"), lines);
// 复制文件
FileUtils.copyFile(srcFile, destFile);

1.1.4 Google Guava 工具类库

maven 依赖:

com.google.guava guava 30.1.1-jre

1.1.4.1 创建集合

List<String> list = Lists.newArrayList();
List<Integer> list = Lists.newArrayList(1, 2, 3);
// 反转list
List<Integer> reverse = Lists.reverse(list);
System.out.println(reverse); // 输出 [3, 2, 1]
// list集合元素太多,可以分成若干个集合,每个集合10个元素
List<List<Integer>> partition = Lists.partition(list, 10);  Map<String, String> map = Maps.newHashMap();
Set<String> set = Sets.newHashSet();

1.2 java 常见的代码规范

1.2.1 使用Collection.isEmpty() 检测空

​ 使用Collection.size() 来检测是否为空在逻辑上没有问题,但是使用Collection.isEmpty() 使得代码更易读,并且可以获得更好的性能;除此之外,任何Collection.isEmpty() 实现的时间复杂度都是O(1) ,不需要多次循环遍历,但是某些通过Collection.size() 方法实现的时间复杂度可能是O(n)。O(1)纬度减少循环次数 例子

反例:

LinkedList<Object> collection = new LinkedList<>();
if (collection.size() == 0){System.out.println("collection is empty.");}

正例

LinkedList<Object> collection = new LinkedList<>();
if (collection.isEmpty()){System.out.println("collection is empty.");}//检测是否为null 可以使用CollectionUtils.isEmpty()
if (CollectionUtils.isEmpty(collection)){System.out.println("collection is null.");

1.2.2 初始化集合时尽量指定其大小

尽量在初始化时指定集合的大小,能有效减少集合的扩容次数,因为集合每次扩容的时间复杂度很可能时O(n),耗费时间和性能。

反例

//初始化list,往list 中添加元素反例:
int[] arr = new int[]{1,2,3,4};
List<Integer> list = new ArrayList<>();
for (int i : arr){list.add(i);
}

正例:

//初始化list,往list 中添加元素正例:
int[] arr = new int[]{1,2,3,4};
//指定集合list 的容量大小List<Integer> list = new ArrayList<>(arr.length);
for (int i : arr){list.add(i);}

1.2.3 若需频繁调用Collection.contains 方法则使用Set

在Java 集合类库中,List的contains 方法普遍时间复杂度为O(n),若代码中需要频繁调用contains 方法查找数据则先将集合list 转换成HashSet 实现,将O(n) 的时间复杂度将为O(1)。

反例:

//频繁调用Collection.contains() 反例
List<Object> list = new ArrayList<>();
for (int i = 0; i <= Integer.MAX_VALUE; i++){//时间复杂度为O(n)
if (list.contains(i))System.out.println("list contains "+ i);}

正例:

//频繁调用Collection.contains() 正例List<Object> list = new ArrayList<>();Set<Object> set = new HashSet<>();
for (int i = 0; i <= Integer.MAX_VALUE; i++){//时间复杂度为O(1)
if (set.contains(i)){System.out.println("list contains "+ i);}}

1.2.4 使用静态代码块实现赋值静态成员变量

对于集合类型的静态成员变量,应该使用静态代码块赋值,而不是使用集合实现来赋值。

反例:

//赋值静态成员变量反例
private static Map<String, Integer> map = new HashMap<String, Integer>(){{map.put("Leo",1);
map.put("Family-loving",2);
map.put("Cold on the out side passionate on the inside",3);}};
private static List<String> list = new ArrayList<>(){{list.add("Sagittarius");
list.add("Charming");
list.add("Perfectionist");}};

正例:

//赋值静态成员变量正例
private static Map<String, Integer> map = new HashMap<String, Integer>();
static {map.put("Leo",1);
map.put("Family-loving",2);
map.put("Cold on the out side passionate on the inside",3);}private static List<String> list = new ArrayList<>();
static {list.add("Sagittarius");
list.add("Charming");
list.add("Perfectionist");}

1.2.5 工具类中屏蔽构造函数

工具类是一堆静态字段和函数的集合,其不应该被实例化;但是,Java 为每个没有明确定义构造函数的类添加了一个隐式公有构造函数,为了避免不必要的实例化,应该显式定义私有构造函数来屏蔽这个隐式公有构造函数。

反例:

public class PasswordUtils {//工具类构造函数反例
private static final Logger LOG = LoggerFactory.getLogger(PasswordUtils.class);public static final String DEFAULT_CRYPT_ALGO = "PBEWithMD5AndDES";public static String encryptPassword(String aPassword) throws IOException {return new PasswordUtils(aPassword).encrypt();}

正例:

public class PasswordUtils {//工具类构造函数正例
private static final Logger LOG = LoggerFactory.getLogger(PasswordUtils.class);//定义私有构造函数来屏蔽这个隐式公有构造函数
private PasswordUtils(){}public static final String DEFAULT_CRYPT_ALGO = "PBEWithMD5AndDES";public static String encryptPassword(String aPassword) throws IOException {return new PasswordUtils(aPassword).encrypt();}

1.2.6 删除未使用的局部变量、方法参数、私有方法、字段和多余的括号

### 1.2.7  **删除多余的异常捕获并抛出 ** (需补充)

用catch 语句捕获异常后,若什么也不进行处理,就只是让异常重新抛出,这跟不捕获异常的效果一样,可以删除这块代码或添加别的处理。

//多余异常反例
private static String fileReader(String fileName)throws IOException{try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {String line;StringBuilder builder = new StringBuilder();
while ((line = reader.readLine()) != null) {builder.append(line);}
return builder.toString();} catch (Exception e) {//仅仅是重复抛异常 未作任何处理
throw e;}
}

正例:

//多余异常正例
private static String fileReader(String fileName)throws IOException{try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {String line;StringBuilder builder = new StringBuilder();
while ((line = reader.readLine()) != null) {builder.append(line);}
return builder.toString();
//删除多余的抛异常,或增加其他处理:
/*catch (Exception e) {return "fileReader exception";}*/}
}

1.2.8 字符串转化使用String.valueOf(value) 代替 " " + value (需补充)

把其它对象或类型转化为字符串时,使用String.valueOf(value) 比 “”+value 的效率更高。

反例:

//把其它对象或类型转化为字符串反例:
int num = 520;
// "" + value
String strLove = "" + num;

正例:

//把其它对象或类型转化为字符串正例:
int num = 520;
// String.valueOf() 效率更高
String strLove = String.valueOf(num);

1.2.9 避免使用BigDecimal(double)

BigDecimal(double) 存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。

反例:

// BigDecimal 反例
BigDecimal bigDecimal = new BigDecimal(0.11D);

正例:

// BigDecimal 正例
BigDecimal bigDecimal1 = bigDecimal.valueOf(0.11D);

2. 设计模式

2.1 装饰者模式订阅

2.1.1 定义

装饰模式又称,包装模式。装饰模式是以客户端透明的方式扩展对象的功能 是一种继承的替代方案。

2.1.2职责

  • 动态给对象增加新的功能
  • 装饰模式是一种用于替代,继承的技术,无需通过继承增加子类就能扩展 对象的功能。使用对象的关联关系,替代继承关系 更加灵活,同时避免了体系的膨胀。

2.1.3 装饰模式结构

  • 装饰模式类图

  • Component 抽象构建角色 :真是对象(对应上图 ConcreteOperation() 对象)和装饰对象具有相同的接口

    。这样客户端对象就能以与 真是对象相同的方式同装饰对象交互了。

  • ConcreteComponent 具体构建的角色(真是对象) :定义一个接收附加责任的类。

  • Decorator装饰角色 持有构建角色的引用。装饰对象接收客户端的请求,并把这些请求转发给真是的对象。这样,就能在真是对象调用前后增加新的功能。

  • ConcreteDecorate 具体的装饰角色:负责给构建对象增加新的功能。

2.1.3 举一个简单的例子

举一个简单的汽车例子,创造每一种汽车都需要继承父类进行实现,如下图 那么当我们需要,既能路上行驶,又能水上行驶,又得继承父类。

以后每增加一种新功能的汽车都需要增一个类,这样的话会创建大量的类。这时候就能使用装饰类了。

代码示例:

抽象构件

public interface AbstractCar {void move();
}  

具体构建

public class Car implements AbstractCar{public void move() {System.out.println("路上行驶");}
}

装饰角色

public class SuperCar implements AbstractCar{protected AbstractCar car;public SuperCar(AbstractCar car){this.car=car;}public void move() {car.move();}}

具体装饰 角色

/*** 飞行汽车
*/   ublic class FlyCar extends SuperCar{public FlyCar(AbstractCar car) {super(car);}public void fly() {System.out.println("空中行驶汽车");}@Overridepublic void move() {super.move();fly();}}/*** 水上汽车*/
public class WaterCar extends SuperCar{public WaterCar(AbstractCar car) {super(car);}public void swim() {System.out.println("水上行驶汽车");}@Overridepublic void move() {super.move();swim();}}

客户端

public class Client {public static void main(String[] args) {Car car=new Car();car.move();System.out.println("------增加新功能,飞行------");FlyCar flyCar=new FlyCar(car);flyCar.move();System.out.println("------新增加功能,水上行驶-----");WaterCar waterCar=new WaterCar(car);waterCar.move();System.out.println("-----新增加两个功能,飞行与水上行驶-----");WaterCar waterCar2=new WaterCar(flyCar);waterCar2.move();}}//输出结果
路上行驶
------增加新功能,飞行------
路上行驶
空中行驶汽车
------新增加功能,水上行驶-----
路上行驶
水上行驶汽车
-----新增加两个功能,飞行与水上行驶-----
路上行驶
空中行驶汽车
水上行驶汽车

2.1.4 另一个很经典的一个场景

  • 咖啡类型 espresso(意大利咖啡),shortblack,LongBlack(美食咖啡),Decaf(无因咖啡)
  • 调料 Milk ,Soy(豆浆),Chocolate
  • 费用 不同的咖啡价格是不同的,而且有 咖啡+调料的类型组合 每个咖啡,都有自己的单价,咖啡+调料也有自己的单价。
  • 要求 扩展咖啡的种类的时候,具有很好的扩展性,改动方便,维护方便。
  • 总结:看到需求,首先是问题的抽象能力,将问题抽象出来,这个抽象能力非常重要。

2.1.5 需求抽象出来

  1. 看到每个咖啡,都有自己的cost(花费)和description(描述)可以知道咖啡共有的属性和行为。
  2. 看到问题后,手动画图或者用软件画出类图 ,遇到问题,首先是下手,做软件行业,就是要下手设计,大家都能想到的如下类图设计

咖啡类型就像是构件,调料就是具体的装饰类,给构件增加新的功能;

2.1.6 具体的类图

装饰者模式,更像俄罗斯的套娃,一层一层的嵌套
看到类图后你会发现,其实就 当前类A 中 含有A属性。
类图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zOXHv3mV-1649327214024)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220302211118098.png)]

代码: 见idea

2.1.7 装饰模式的优点

  • 扩展对象功能,比继承灵活,不会导致类个数急剧增加。
  • 可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象。
  • 具体构 件 类和具体装饰类可以独立变化,用户可以根据需要自己增加新的 具体构件子类和具体装饰子类。

2.1.8 缺点

  • 产生很多小对象。大量小的对象占据内存,一定程度上影响性能。
  • 装饰模式易出错,调试排查比较麻烦。

2.2 桥接者模式

商城中常见的模式 ,以电脑分类,如何处理商品分类销售问题

  • 我们可以使用多层继承实现关系如下

    >

代码省略: 存在的问题,

  • 扩展问题

    1. 如果要增加新的电脑类型:如平板电脑,则要增加 各个品牌下面的类。
    2. 如果新增加品牌,也要增加各个电脑下的类。
    • 违反了单一职责原则

    ​ 一个类:如联想笔记本电脑,有两个引起这个类变化的原因:品牌及电脑的类型。

    总结:某些由于自身的逻辑,它具有两个或者多个维度的变化,为了应对这种“多维度变化”,并且利用面向对象 的技术来,使得该类能轻松的沿着多个方向变化,而有不引入额外的复杂度。引入bridge模式。

2.2.1 桥接模式概念

概念:把抽象(abstraction)和行为实现分开(implement)从而保持各部分的独立性以及对功能的扩展

2.2.2 结构图

上面场景中有两个变化的维度,电脑类型和电脑品牌,将上面的代码通过桥接模式实现:

2.2.3 具体代码

电脑品牌维度

/*** 电脑品牌维度接口*/
public interface Brand {void nane();
}class Lenovo implements Brand{@Overridepublic void nane() {System.out.println("联想电脑");}
}class Dell implements Brand{@Overridepublic void nane() {System.out.println("戴尔电脑");}
}

电脑类型维度

/*** 电脑类型维度*/
public class Computer{protected Brand brand;public Computer(Brand brand){this.brand=brand;}public void sale(){brand.nane();}
}
class Desktop extends Computer{public Desktop(Brand brand) {super(brand);}@Overridepublic void sale() {super.sale();System.out.println("销售台式机");}
}class Laptop extends Computer{public Laptop(Brand brand) {super(brand);}@Overridepublic void sale() {super.sale();System.out.println("销售笔记本");}}

客户端

/*** 客户端*/
public class Client {public static void main(String[] args) {Computer len=new Desktop(new Lenovo());len.sale();}
}//输出结果
联想电脑
销售台式机

总结:这样将 电脑品牌和电脑类型两个维度,分离开并且组合使用,这样在增加品牌或类型更加简单。

2.2.4 桥接模式的设计要点和适用性

  • 设计要点

处理多层继承结构,处理多维度变化的场景,将更维度设计成独立的继承模块,使各个维度可以独立扩展在抽象层。

  • 适用性

    1. 如果一个系统需要在构件的抽象化角色和具体化角色之间,增加更多的灵活性,避免在两个层次之间建立静态的关系。
    2. 设计要求实现化角色的任何改变不应该影响客户端,或者说实现化角色的改变对客户端是完全透明的。
    3. 一个构件多余一个抽象化角色和实现化角色,系统需要它们之间互相解耦。
    4. 虽然系统中使用继承没有问题,但由于抽象化角色和具体化角色需要独立化,设计要求独立管理两者。

2.2.5 装饰模式和桥接模式的区别

  • 两个模式都是为了解决过多子类对象的问题。但他们的诱因不同,桥接模式是对象自身现有机制沿着多个维度变化,是既有部分不稳定。装饰模式是为了增加新的功能

2.3 观察者模式

场景: 是一种 一对多的关系,进一步理解为 消息订阅模式

Subject 被观察者 也叫做 主题
Observer  观察者  也叫订阅者
理解:被观察者 通知观察者自己的状态变化   被观察者中注册了,多个观察者对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rPyA2BFY-1649327214026)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220302213558321.png)]

2.4 责任链模式

2.5 建造者模式

2.5.1 概念

将复杂对象的构建和它的表示,使得同样的构建过程有不同的创建方式。

2.6 组合这模式

2.6.1 组合模式的概念

概念 把部分和整体用树形结构来表示 ,从而使客户端可以使用统一的方式对,部分对象和整体对象就行管理。

2.6.2 组合模式结构

抽象构件(Conponent) 角色: 所有类共有接口,定义叶子节点和容器共同点

叶子(Leaf)构件角色:在组合中表示叶子节点对象,叶子节点五子节点。

容器(Composite)构件角色: 有容器特征,可以用来存储子节点,在Component接口中实现与子节点有关操作,如增加(add)和删除(remove)等。

2.6.3组合模式工作分析

  • 组合模式为处理树形结构,提供了完美的解决方案,描述了如何将容器和叶子节点进行递归组合,使得用户在使用时, 可以一致性的对待容器和叶子。
  • 当容器对象的指定方法被调用时,将遍历整个树形结构,寻找包含这个方法的成员,并调用执行。其中使用递归调用机制对整个机构进行处理。

下面是通过简单秒杀的例子,使用组合

抽象构建

public interface AbstractFile {void killVirus();//杀毒
}

叶子构件

class ImageFile implements AbstractFile{private String name;public ImageFile(String name){this.name=name;}public void killVirus() {System.out.println("---对图像文件"+name+"杀毒");}}
class TextFile implements AbstractFile{private String name;public TextFile(String name){this.name=name;}public void killVirus() {System.out.println("---对文本文件"+name+"杀毒");}}

容器构建

class Folder implements AbstractFile{private String name;private ArrayList<AbstractFile> list=new ArrayList<AbstractFile>();public Folder(String name){this.name=name;}public void add(AbstractFile file){list.add(file);}public void remove(AbstractFile file){list.remove(file);}public AbstractFile getChild(int index){return list.get(index);}public void killVirus() {System.out.println("---对文件夹"+name+"杀毒");for(AbstractFile file:list){file.killVirus();}}}

客户端

public class Client {public static void main(String[] args) {Folder f1;AbstractFile f2,f3;f1=new Folder("我的收藏");f2=new ImageFile("my.jpg");f3=new TextFile("my.txt");f1.add(f2);f1.add(f3);f1.killVirus();}}//输出结果:
---对文件夹我的收藏杀毒
---对图像文件my.jpg杀毒
---对文本文件my.txt杀毒  

2.7 策略模式

组合关系

2.8 外观模式

2.8.1 概念

  • 外观模式(也称门面模式)定义了一个高层接口,为子系统中的一组接口提供了,一致的界面,从而使子系统更加容易使用。

2.9 命令模式

2.9.1 概念

将一个请求封装为对象,从而使我们可用不同的请求,对客户进行参数化;对请求排队或者记录请求日志,以及支持撤销操作,以及支持撤销操作。也称为:动作(Action)模式,事务(transaction)模式。

2.9.2 模式结构

  • Conmmand 抽象命令类: 声明执行操作接口

  • ConcreteCommand 具体命令类:通常持有 一个接收者对象并绑定一个动作,调用接收者相应的动作,以实现execute方法。

  • invoker 调用者/请求者:请求的发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联。在程序运行时,将调用命令对象的execute() 间接调用接收者的相关工作。

  • Receiver接收者:接受者执行与请求相关的操作,具体实现对请求业务的处理。

2.9.3 结构图

Receiver接受者

/*** 真正的命令执行者*/
public class Receiver {public void action(){System.out.println("执行命令----");}public void unAction(){System.out.println("撤销命令----");}}

command 抽象命令类

/*** 抽象命令接口*/
public interface Command {void  execute();//执行命令void  cancel();//取消命令 }   

ConcreteCommand具体命令类

/*** 具体命令类*/
public class ConcreteCommand implements Command{private Receiver receiver;public ConcreteCommand(Receiver receiver) {super();this.receiver = receiver;}public void execute() {//可进行执行命令前相关操作receiver.action();//执行命令//可进行执行命令后相关操作}public void cancel() {receiver.unAction();}
}

Invoke 调用者/请求者

public class Invoker {private Command command;  //可以是多个命令public Invoker(Command command) {super();this.command = command;}//执行命令public void runCommand(){command.execute();}//取消命令public void cancelCommand(){command.cancel();}}

客户端

public class Client {public static void main(String[] args) {//创建接收者Receiver receiver=new Receiver();//创建命令对象,并设置接收者Command command=new ConcreteCommand(receiver);//创建调用者,设置命令Invoker invoker=new Invoker(command);invoker.runCommand();invoker.cancelCommand();}
}//输出结果
执行命令----
撤销命令----   

2.9.3建议看这个代码

应用 :模拟对电视机的操作有开机、关机、换台命令。代码如下

//执行命令的接口
public interface Command {void execute();
}
//命令接收者Receiver
public class Tv {public int currentChannel = 0;public void turnOn() {System.out.println("The televisino is on.");}public void turnOff() {System.out.println("The television is off.");}public void changeChannel(int channel) {this.currentChannel = channel;System.out.println("Now TV channel is " + channel);}
}
//开机命令ConcreteCommand
public class CommandOn implements Command {private Tv myTv;public CommandOn(Tv tv) {myTv = tv;}public void execute() {myTv.turnOn();}
}
//关机命令ConcreteCommand
public class CommandOff implements Command {private Tv myTv;public CommandOff(Tv tv) {myTv = tv;}public void execute() {myTv.turnOff();}
}
//频道切换命令ConcreteCommand
public class CommandChange implements Command {private Tv myTv;private int channel;public CommandChange(Tv tv, int channel) {myTv = tv;this.channel = channel;}public void execute() {myTv.changeChannel(channel);}
}
//可以看作是遥控器Invoker
public class Control {private Command onCommand, offCommand, changeChannel;public Control(Command on, Command off, Command channel) {onCommand = on;offCommand = off;changeChannel = channel;}public void turnOn() {onCommand.execute();}public void turnOff() {offCommand.execute();}public void changeChannel() {changeChannel.execute();}
}
//测试类Client
public class Client {public static void main(String[] args) {// 命令接收者ReceiverTv myTv = new Tv();// 开机命令ConcreteCommondCommandOn on = new CommandOn(myTv);// 关机命令ConcreteCommondCommandOff off = new CommandOff(myTv);// 频道切换命令ConcreteCommondCommandChange channel = new CommandChange(myTv, 2);// 命令控制对象InvokerControl control = new Control(on, off, channel);// 开机control.turnOn();// 切换频道control.changeChannel();// 关机control.turnOff();}
}

执行结果

The televisino is on.
Now TV channel is 2
The television is off.

2.9.4 命令模式的优缺点

  • 优点
  1. 降低对象的耦合度。
  2. 新的命令很容易加入到系统中。
  3. 可以很容易的设计一套命令。
  4. 调用同一个方法不同功能
  • 缺点
  1. 使用命令模式可能会导致某些系统有很多具体的命令类,因为针对每一个命令需要设计一个命令类,因此某些系统可能需要大量的命令类,将影响命令模式的使用。
  • 总结

    1. 命令模式本质是对,命令进行封装,将发出命令的责任和执行命令的责任分割开。
    2. 每一个命令都是一个操作,请求一方发出命令,要求执行一个动作;接收方收到请求,并执行请求。
    3. 命令模式允许请求的一方和接收的一方,独立开来,使得请求方不知道接收方的接口,更不知道请求是怎么被接收,以及是否被执行,何时被执行,以及怎么被执行。
    4. 命令模式使请求本身成为对象,这个对象和其他对象可以被存储和传递。
    5. 命令模式的关键在于引入抽象接口,且发送者针对抽象接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

java后端分享整理相关推荐

  1. 横扫阿里、滴滴、美团后,3年经验的Java后端妹子整理出这份厚厚的面经!

    横扫阿里.滴滴.美团后,3年经验的Java后端妹子整理出这份厚厚的面经! 扫描下方海报二维码,试听课程: (课程详细大纲,请参见文末) ================================ ...

  2. Java后端学习视频和资源分享

    文章目录 基础 JavaWeb 操作系统 数据结构与算法 框架 Mybatis Spring SpringMVC Mybatis_Plus Springboot Structs2 Hibernate ...

  3. 以技术面试官的经验分享毕业生和初级程序员通过面试的技巧(Java后端方向)...

    本来想分享毕业生和初级程序员如何进大公司的经验,但后来一想,人各有志,有程序员或许想进成长型或创业型公司或其它类型的公司,所以就干脆来分享些提升技能和通过面试的技巧,技巧我讲,公司你选,两厢便利. 毕 ...

  4. 算法转 Java 后端,2021秋招斩获腾讯、京东、百度等大厂 offer 面经分享

    这是一篇来自算法转Java后端的一位读者的投稿!文章主要分享了作者从迷茫崩溃到最终斩获腾讯.京东.百度等大厂 offer 的经历.文章内容很全面.真实,相信可以对正在准备面试的小伙伴有帮助! 看到公众 ...

  5. 算法转 Java 后端,2021秋招斩获腾讯、京东、百度等大厂 offer 面经分享!

    这是一篇来自算法转Java后端的一位读者的投稿!文章主要分享了作者从迷茫崩溃到最终斩获腾讯.京东.百度等大厂 offer 的经历.文章内容很全面.真实,相信可以对正在准备面试的小伙伴有帮助! 个人简介 ...

  6. 程序员分享:最近面试 Java 后端开发的感受

    上周,密集面试了若干位Java后端候选人,工作经验在3到5年间.我的标准其实不复杂: 第一能干活,第二Java基础要好,第三最好熟悉些分布式框架.我相信其它公司招初级开发时,应该也照着这个标准来面的. ...

  7. 【面经分享】2022阿里Java后端实习面经,已上岸

    阿里JAVA后端 第一轮:电话初面试 第二轮:技术面谈 第三轮:电话初面试 第四轮:HR最后确认 一面: 首先确认对阿里的意向度(如果异地更会考虑对工作地点(杭州)的意向度!阿里很看重这个):其次面试 ...

  8. Java后端开发工程师技术栈整理

    文章目录 Java后端开发工程师技术栈整理 常用工具 Java IDE 数据库客户端 数据库建模工具 SSH客户端 文本编辑器 Markdown编辑器 API调试工具 浏览器 压力测试工具 DevOp ...

  9. 【软件创新实验室2021年寒假集训】Java后端开发漫谈及感悟分享

    系列文章目录 [软件创新实验室2021年寒假集训]汇总篇 20级Java培训 第一天:[软件创新实验室2021年寒假集训]Java技术培训--Java前置知识学习 第二天:Java基础(一) 第三天: ...

最新文章

  1. c语言为什么提供函数声明机制,通过实战理解C语言精要——函数篇
  2. 提升购物体验,跨境电商如何做企业管理?
  3. c语言两个for语句并列执行_C语言两个for语句如何并列编写?
  4. kafka分区与分组原理_Kafka工作原理
  5. 使用maven根据JSON文件自动生成Java POJO类(Java Bean)源文件
  6. I/O端口及其寻址方式
  7. Django(6)-orm
  8. 鱼哥,我怕蛇,可以搞Python么?
  9. 开源日志审计系统_详解mysql数据库审计特点、实现方案及审计插件部署演示
  10. OpenCV_信用卡识别代码_唐宇迪实战项目
  11. 织梦php 文章采集规则,采集规则的管理 --- 采集节点管理
  12. 【多字典公共键】快速找到多个字典的公共键及非公共键
  13. JVM调优实践:记录初次JVM调优经历
  14. 40个幼儿园小故事,每天讲一个给小朋友~(赶紧收藏)
  15. 房地产里有多少“三季人”?
  16. 什么是计算机软件 软件定义,软件定义_软件定义教程_软件定义视频教程 _课课家...
  17. iOS获取设备的序列号
  18. VPX高速信号处理板设计资料第240篇:4C6678_K7_DDR3_VPX高速信号处理板
  19. mib2c : You didn‘t give mib2c a valid OID to start with.解决
  20. 73. 使用自定义 Query 实现 SAP UI5 页面路由的书签功能

热门文章

  1. 微信小程序几种常用弹窗提示
  2. JS之数组元素排序方法sort
  3. python appium自动化测试平台开发,Python+Appium实现自动化测试
  4. 百度地图gif图标_华为手机误删照片怎么找回?手机怎么快速制作GIF动图
  5. 正弦定理和余弦定理_那些让你加快解题速度的高中数学公式-26 利用三正弦、三余弦定理快速解题...
  6. activiti高亮显示图片_【正点原子FPGA连载】第二十章SD卡读BMP图片HDMI显示实验领航者 ZYNQ 之嵌入式开发指南...
  7. oracle 添加字段
  8. Spark-Streaming基础
  9. 常用的方法论-PARR
  10. unity3d 鼠标延各个方向拖拽物体