迪米特原则(Law of Demeter):在系统设计中,一个类应该对自己需要耦合或调用的类知道得最少,尽量降低类与类之间的耦合,可以通过引用一个合理的第三者来降低现有的对象之间的耦合度。
单一职责原则(Single Responsibility Principle):在系统设计中,一个类或接口只有一个职责,它只负责一件事情。
接口隔离原则(Interface Segregation Principle):在系统设计中,客户端不应该依赖它不需要的接口,也无需实现不需要知道的方法,类之间的依赖关系应该建立在最小的接口上。
依赖倒置原则(Dependence Inversion Principle):在系统设计中,上层模块不应该依赖底层模块,它们都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。
里氏替换原则(Liskov Substitution Principle):在系统设计中,所有用到基类的地方都可以替换成子类,且程序还可以正常运行。
开放封闭原则(Open Closed Principle):在系统设计中,一个软件实体应该是可扩展,而不可修改的,即对扩展开放,对修改关闭。
单例模式是我们最常见的设计模式之一,它是指一个类只有一个实例,并且该类能自行创建这个实例的一种模式。通常单例模式有五种写法,下面分别介绍这五种写法的区别,代码示例:
/**
* 单例模式,也叫单子模式,是一种常用的软件设计模式。
* 在应用这个模式时,单例对象的类必须保证只有一个实例存在。
* 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
*/
public class SingleMode {
/**
* 饿汉模式
* 优点:它基于 classloader 机制避免了多线程的同步问题,另外它没有加锁,执行效率高
* 缺点:当类加载时就迫不及待的被初始化了,浪费内存
*/
private static SingleMode instance = new SingleMode();
/**
* 单例模式,提供一个静态对象给外界访问
*
* @return
*/
public static SingleMode getInstance() {
return instance;
}
/**
* 构造函数声明为私有的,拒绝外界直接访问
*/
private SingleMode() {
}
}
/**
* 单例模式,也叫单子模式,是一种常用的软件设计模式。
* 在应用这个模式时,单例对象的类必须保证只有一个实例存在。
* 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
*/
public class SingleMode {
/**
* 懒汉模式
* 优点:懒加载避免浪费内存,另外它没有同步加锁,执行效率高
* 缺点:线程不安全,在多线程的情况下它其实还算不上单例模式
*/
private static SingleMode instance;
/**
* 单例模式,提供一个静态对象给外界访问
*
* @return
*/
public static SingleMode getInstance() {
if (instance == null) {
instance = new SingleMode();
}
return instance;
}
/**
* 构造函数声明为私有的,拒绝外界直接访问
*/
private SingleMode() {
}
}
/**
* 单例模式,也叫单子模式,是一种常用的软件设计模式。
* 在应用这个模式时,单例对象的类必须保证只有一个实例存在。
* 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
*/
public class SingleMode {
/**
* 懒汉模式
* 优点:懒加载避免浪费内存,线程安全
* 缺点:加了同步锁,执行效率相对低
*/
private static SingleMode instance;
/**
* 单例模式,提供一个静态对象给外界访问
*
* @return
*/
public static synchronized SingleMode getInstance() {
if (instance == null) {
instance = new SingleMode();
}
return instance;
}
/**
* 构造函数声明为私有的,拒绝外界直接访问
*/
private SingleMode() {
}
}
/**
* 单例模式,也叫单子模式,是一种常用的软件设计模式。
* 在应用这个模式时,单例对象的类必须保证只有一个实例存在。
* 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
*
* 双锁机制的出现是为了解决前面同步问题和性能问题
* synchronized能保证可见性,为什么单例模式还需要加volatile关键字?
* 这里加锁确实能够保证这个对象不会被new两次,但不能保证对象的创建过程不被重排序
* volatile:
* 当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
* 而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。
* 另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。
*
*/
public class SingleMode {
/**
* 懒汉模式
* 优点:懒加载避免浪费内存,双锁机制,线程安全,效率高
* 缺点:--
*/
private volatile static SingleMode instance;
/**
* 单例模式,提供一个静态对象给外界访问
*
* @return
*/
public static SingleMode getInstance() {
if (instance == null) {
synchronized (SingleMode.class) {
if (instance == null) {
instance = new SingleMode();
}
}
}
return instance;
}
/**
* 构造函数声明为私有的,拒绝外界直接访问
*/
private SingleMode() {
}
}
/**
* 单例模式,也叫单子模式,是一种常用的软件设计模式。
* 在应用这个模式时,单例对象的类必须保证只有一个实例存在。
* 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
*
* 这种单例模式是Josh Bloch 提倡的方式,它的写法更加简洁,线程安全,避免多次实例化,并防止反序列化重新创建新的对象
*/
public enum SingleMode {
INSTANCE;
public void whateverMethod() {
}
}
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。
使用场景:
代码示例:
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Repository repository = new Repository();
repository.add("张三");
repository.add("李四");
repository.add("王五");
repository.add("赵六");
repository.add("老七");
// for循环写法:
for (Iterator iterator = repository.iterator(); iterator.hasNext(); ) {
Object obj = iterator.next();
System.out.println("for循环写法: " + obj);
}
// while循环写法:
Iterator<Repository> entries = repository.iterator();
while (entries.hasNext()) {
System.out.println("while循环写法: " + entries.next());
}
}
}
import java.util.ArrayList;
import java.util.List;
/**
* 具体的容器类
*/
public class Repository implements Container {
private List<Object> list = new ArrayList<>();
@Override
public Iterator iterator() {
return new IIterator();
}
@Override
public void add(Object object) {
list.add(object);
}
/**
* 具体的迭代器类
*/
private class IIterator implements Iterator {
int index;
@Override
public boolean hasNext() {
if (index < list.size()) {
return true;
}
return false;
}
@Override
public Object next() {
if (this.hasNext()) {
return list.get(index++);
}
return null;
}
}
}
/**
* 迭代器接口
* @param
*/
public interface Iterator<T> {
boolean hasNext();
T next();
}
/**
* 容器接口
*/
public interface Container {
Iterator iterator();
void add(Object object);
}
策略模式提供了对“开闭原则”的完美支持,在策略模式中,通过不同策略类进行封装不同的算法,只需要传入相对应的策略类即可实现算法或行为,随着需要的算法策略的增多,策略类也会增多,不同的策略类相互独立,使用策略模式时可以避免使用多重条件判断。
下面以房贷计算器为例,先定义一个计算类的策略接口,不同的策略类都实现这个接口,通过传入一个对象,该对象包含一切需要传入的计算数值,然后可以在不同的策略类中实现不同的算法,最后可以在需要输出不同算法时候传入不同策略类即可实现。策略模式会由于各种不同策略的增多,而产生很多个策略类,这是这种设计模式的缺点,策略模式会造成很多个不同的策略类,不过我们可以通过享元模式在一定程度上减少对象的数量。
代码示例:
// 先定义一个计算实体类
public class CalculatorEntity implements Serializable {
// 贷款总额 (单位:万元)
private double totalLoan;
// 公积金贷款总额,商贷和公积金贷款组合模式下使用
private double providentLoan;
// 贷款类型(商业/公积金/组合)
private CalculatorStrategy.LoanType loanType;
// 还款方式(等额本息/等额本金)
private CalculatorStrategy.RepaymentWay repaymentWay;
// 贷款期限 (单位:年)
private int loanTerm;
// 贷款利率,银行利率或者公积金利率 (例如:4.9)
private double loanRate;
// 公积金利率,商贷和公积金贷款组合模式下使用 (目前固定为3.25)
private double providentRate = 3.25;
public double getTotalLoan() {
return totalLoan;
}
public void setTotalLoan(double totalLoan) {
this.totalLoan = totalLoan;
}
public double getProvidentLoan() {
return providentLoan;
}
public void setProvidentLoan(double providentLoan) {
this.providentLoan = providentLoan;
}
public CalculatorStrategy.LoanType getLoanType() {
return loanType;
}
public void setLoanType(CalculatorStrategy.LoanType loanType) {
this.loanType = loanType;
}
public CalculatorStrategy.RepaymentWay getRepaymentWay() {
return repaymentWay;
}
public void setRepaymentWay(CalculatorStrategy.RepaymentWay repaymentWay) {
this.repaymentWay = repaymentWay;
}
public int getLoanTerm() {
return loanTerm;
}
public void setLoanTerm(int loanTerm) {
this.loanTerm = loanTerm;
}
public double getLoanRate() {
return loanRate;
}
public void setLoanRate(double loanRate) {
this.loanRate = loanRate;
}
public double getProvidentRate() {
return providentRate;
}
}
// 定义一个接口
public interface CalculatorStrategy {
// 贷款类型
enum LoanType {
BUSINESS, PROVIDENT, COMBINATION
}
// 还款方式
enum RepaymentWay {
AMOUNT, INTEREST
}
// 做计算
double doCalculator(CalculatorEntity entity);
}
// 具体策略类:每月还款 / 首月还款
public class MonthlyRepayment implements CalculatorStrategy {
@Override
public double doCalculator(CalculatorEntity entity) {
// 贷款总月份
int months = entity.getLoanTerm() * 12;
// 银行贷款月利率
double monthRate = entity.getLoanRate() / (100 * 12);
// 公积金贷款月利率
double providentMonthRate = entity.getProvidentRate() / (100 * 12);
// 输入结果
double result;
// 商业贷款或者公积金贷款
if (entity.getRepaymentWay() == RepaymentWay.AMOUNT) {
// 等额本金还款方式,计算首月还款总金额
result = (entity.getTotalLoan() / months + entity.getTotalLoan() * monthRate);
} else {
// 等额本息还款方式,计算每月还款总金额
result = (entity.getTotalLoan() * monthRate * Math.pow((1 + monthRate), months)) / (Math.pow((1 + monthRate), months) - 1);
}
if (entity.getLoanType() == LoanType.COMBINATION) {
// 组合贷款,区分商业贷款和公积金贷款
if (entity.getRepaymentWay() == RepaymentWay.AMOUNT) {
// 等额本金还款方式,计算首月还款总金额
result = result + (entity.getProvidentLoan() / months + entity.getProvidentLoan() * providentMonthRate);
} else {
// 等额本息还款方式,计算每月还款总金额
result = result + (entity.getProvidentLoan() * providentMonthRate * Math.pow((1 + providentMonthRate), months)) / (Math.pow((1 + providentMonthRate), months) - 1);
}
}
return result;
}
}
// 具体策略类:贷款月数
public class NumberOfLoans implements CalculatorStrategy {
@Override
public double doCalculator(CalculatorEntity entity) {
return entity.getLoanTerm() * 12;
}
}
// 具体策略类:支付利息
public class PayInterest implements CalculatorStrategy {
@Override
public double doCalculator(CalculatorEntity entity) {
// 贷款总月份
int months = entity.getLoanTerm() * 12;
// 银行贷款月利率
double monthRate = entity.getLoanRate() / (100 * 12);
// 公积金贷款月利率
double providentMonthRate = entity.getProvidentRate() / (100 * 12);
// 输入结果
double result;
if (entity.getRepaymentWay() == RepaymentWay.AMOUNT) {
// 等额本金还款方式,还款总利息
result = ((months + 1) * entity.getTotalLoan() * monthRate / 2);
} else {
// 等额本息还款方式,还款总利息
double preLoan = (entity.getTotalLoan() * monthRate * Math.pow((1 + monthRate), months)) / (Math.pow((1 + monthRate), months) - 1);
double totalMoney = preLoan * months;
result = (totalMoney - entity.getTotalLoan());
}
if (entity.getLoanType() == LoanType.COMBINATION) {
// 组合贷款,区分商业贷款和公积金贷款
if (entity.getRepaymentWay() == RepaymentWay.AMOUNT) {
// 等额本金还款方式,还款总利息
result = result + ((months + 1) * entity.getProvidentLoan() * providentMonthRate / 2);
} else {
// 等额本息还款方式,还款总利息
double preLoan = (entity.getProvidentLoan() * providentMonthRate * Math.pow((1 + providentMonthRate), months)) / (Math.pow((1 + providentMonthRate), months) - 1);
double totalMoney = preLoan * months;
result = result + (totalMoney - entity.getProvidentLoan());
}
}
return result;
}
}
// 具体策略类:还款总额
public class TotalRepayment implements CalculatorStrategy {
@Override
public double doCalculator(CalculatorEntity entity) {
// 贷款总月份
int months = entity.getLoanTerm() * 12;
// 银行贷款月利率
double monthRate = entity.getLoanRate() / (100 * 12);
// 公积金贷款月利率
double providentMonthRate = entity.getProvidentRate() / (100 * 12);
// 输入结果
double result;
if (entity.getRepaymentWay() == RepaymentWay.AMOUNT) {
// 等额本金还款方式,还款总额 = 贷款总额 + 还款总利息
double interest = (months + 1) * entity.getTotalLoan() * monthRate / 2;
result = (entity.getTotalLoan() + interest);
} else {
// 等额本息还款方式,还款总额 = 每月还款金额 * 贷款总月份
double preLoan = (entity.getTotalLoan() * monthRate * Math.pow((1 + monthRate), months)) / (Math.pow((1 + monthRate), months) - 1);
result = (preLoan * months);
}
if (entity.getLoanType() == LoanType.COMBINATION) {
// 组合贷款,区分商业贷款和公积金贷款
if (entity.getRepaymentWay() == RepaymentWay.AMOUNT) {
// 等额本金还款方式,还款总额 = 贷款总额 + 还款总利息
double interest = (months + 1) * entity.getProvidentLoan() * providentMonthRate / 2;
result = result + (entity.getProvidentLoan() + interest);
} else {
// 等额本息还款方式,还款总额 = 每月还款金额 * 贷款总月份
double preLoan = (entity.getProvidentLoan() * providentMonthRate * Math.pow((1 + providentMonthRate), months)) / (Math.pow((1 + providentMonthRate), months) - 1);
result = result + (preLoan * months);
}
}
return result;
}
}
// 计算类,传入不同的策略类计算不同结果
public class Calculator {
// 计算策略类
private CalculatorStrategy mCalculatorStrategy;
public Calculator(CalculatorStrategy calculatorStrategy) {
this.mCalculatorStrategy = calculatorStrategy;
}
/**
* 做计算
*
* @param entity
* @return
*/
public double doCalculator(CalculatorEntity entity) {
return mCalculatorStrategy.doCalculator(entity);
}
}
// 计算实体类
private static final CalculatorEntity mCalculatorEntity = new CalculatorEntity();
/**
* 点击开始计算
*
* @param v
*/
public void onClickCalculator(View v) {
// 进行房贷计算
mCalculatorEntity.setTotalLoan(totalLoan);
mCalculatorEntity.setProvidentLoan(providentLoan);
mCalculatorEntity.setLoanType(loanType);
mCalculatorEntity.setRepaymentWay(repaymentWay);
mCalculatorEntity.setLoanTerm(mLoanTerm);
mCalculatorEntity.setLoanRate(mLoanRate);
// 做计算
doCalculator(mCalculatorEntity);
}
/**
* 做计算
*
* @param entity
*/
private void doCalculator(CalculatorEntity entity) {
Calculator calculator;
// 还款总额(单位:万元)
calculator = new Calculator(new TotalRepayment());
double totalRepayment = calculator.doCalculator(entity);
// 贷款月数
calculator = new Calculator(new NumberOfLoans());
double numberOfLoans = calculator.doCalculator(entity);
// 支付利息(单位:万元)
calculator = new Calculator(new PayInterest());
double payInterest = calculator.doCalculator(entity);
// 每月还款 / 首月还款 (单位:万元,需要x10000转成元)
calculator = new Calculator(new MonthlyRepayment());
double monthlyRepayment = calculator.doCalculator(entity);
}
工厂模式是一种创建型模式,它实现了对象创建和使用的分离,客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,同时它的扩展性也高,如果想增加一个具体的产品类,只要扩展一个工厂类就行。
下面以加密解密项目(简单工厂)为例,先定义一个抽象的加密类,然后增加其他具体类型的加密类去继承这个抽象的加密类,并且在相对应的回调函数中实现具体算法,最后通过创建加密工厂类以传入参数类型的方式返回一个加密对象,调用者只需要调用它的相关方法即可实现各种算法的加密或解密。
代码示例:
// 抽象的加密类
public abstract class Encrypt {
// 加密的类型
public enum EncryptType {
AES,
DES,
DES3,
RSA
}
// 输出类型
public enum OutputType {
HEX,
BASE64
}
// 默认可选项
protected EncryptFactory.Options mOptions = EncryptFactory.Options.getDefaultOptions();
// 加密字符串
public abstract String encryptString(String key, String data);
// 解密字符串
public abstract String decryptString(String key, String data);
// 加密字符串
public abstract String encryptString(String key, String data, EncryptFactory.Options options);
// 解密字符串
public abstract String decryptString(String key, String data, EncryptFactory.Options options);
}
// 具体的AES加密类
public class AesEncrypt extends Encrypt {
// 加密模式
private static final String CIPHER_MODE = "AES/CFB/NoPadding";
public AesEncrypt() {
super();
}
@Override
public String encryptString(String key, String data) {
return encrypt(key, data, mOptions);
}
@Override
public String decryptString(String key, String data) {
return decrypt(key, data, mOptions);
}
@Override
public String encryptString(String key, String data, EncryptFactory.Options options) {
return encrypt(key, data, options);
}
@Override
public String decryptString(String key, String data, EncryptFactory.Options options) {
return decrypt(key, data, options);
}
/**
* 加密字符串
*
* @param key
* @param data
* @param options
* @return
*/
private String encrypt(String key, String data, Options options) {
try {
if (!TextUtils.isEmpty(data)) {
byte[] bytes = data.getBytes(options.encoding);
bytes = encrypt(key, bytes, options);
if (bytes != null) {
switch (options.output) {
case HEX:
return byteToHex(bytes);
case BASE64:
return byteToBase64(bytes);
default:
return new String(bytes, options.encoding);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
/**
* 加密字节数组
*
* @param key
* @param bytes
* @param options
* @return
*/
private byte[] encrypt(String key, byte[] bytes, Options options) {
try {
if (bytes != null) {
Cipher cipher = Cipher.getInstance(CIPHER_MODE);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKeySpec(key, options), new IvParameterSpec(new byte[cipher.getBlockSize()]));
return cipher.doFinal(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
/**
* 解密字符串
*
* @param key
* @param data
* @param options
* @return
*/
private String decrypt(String key, String data, Options options) {
try {
if (!TextUtils.isEmpty(data)) {
byte[] bytes;
switch (options.output) {
case HEX:
bytes = hexToByte(data);
break;
case BASE64:
bytes = base64ToByte(data);
break;
default:
bytes = data.getBytes();
break;
}
bytes = decrypt(key, bytes, options);
if (bytes != null) {
return new String(bytes, options.encoding);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
/**
* 解密字节数组
*
* @param key
* @param bytes
* @param options
* @return
*/
private byte[] decrypt(String key, byte[] bytes, Options options) {
try {
if (bytes != null) {
Cipher cipher = Cipher.getInstance(CIPHER_MODE);
cipher.init(Cipher.DECRYPT_MODE, getSecretKeySpec(key, options), new IvParameterSpec(new byte[cipher.getBlockSize()]));
return cipher.doFinal(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
/**
* 获取SecretKeySpec对象
*
* @param key
* @param options
* @return
*/
private SecretKeySpec getSecretKeySpec(String key, Options options) {
try {
final String lastKey = patchKey(key, options.bit);
byte[] data = lastKey.getBytes(options.encoding);
return new SecretKeySpec(data, "AES");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
// 具体的DES加密类
public class DesEncrypt extends Encrypt {
// 加密模式
private static final String CIPHER_MODE = "DES";
public DesEncrypt() {
super();
}
@Override
public String encryptString(String key, String data) {
return encrypt(key, data, mOptions);
}
@Override
public String decryptString(String key, String data) {
return decrypt(key, data, mOptions);
}
@Override
public String encryptString(String key, String data, EncryptFactory.Options options) {
return encrypt(key, data, options);
}
@Override
public String decryptString(String key, String data, EncryptFactory.Options options) {
return decrypt(key, data, options);
}
/**
* 加密字符串
*
* @param key
* @param data
* @param options
* @return
*/
private String encrypt(String key, String data, Options options) {
try {
if (!TextUtils.isEmpty(data)) {
byte[] bytes = data.getBytes(options.encoding);
bytes = encrypt(key, bytes, options);
if (bytes != null) {
switch (options.output) {
case HEX:
return byteToHex(bytes);
case BASE64:
return byteToBase64(bytes);
default:
return new String(bytes, options.encoding);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
/**
* 加密字节数组
*
* @param key
* @param bytes
* @param options
* @return
*/
private byte[] encrypt(String key, byte[] bytes, Options options) {
try {
if (bytes != null) {
Cipher cipher = Cipher.getInstance(CIPHER_MODE);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key, options), new SecureRandom());
return cipher.doFinal(bytes);
}
} catch (Throwable e) {
e.printStackTrace();
}
return bytes;
}
/**
* 解密字符串
*
* @param key
* @param data
* @param options
* @return
*/
private String decrypt(String key, String data, Options options) {
try {
if (!TextUtils.isEmpty(data)) {
byte[] bytes;
switch (options.output) {
case HEX:
bytes = hexToByte(data);
break;
case BASE64:
bytes = base64ToByte(data);
break;
default:
bytes = data.getBytes();
break;
}
bytes = decrypt(key, bytes, options);
if (bytes != null) {
return new String(bytes, options.encoding);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
/**
* 解密字节数组
*
* @param key
* @param bytes
* @param options
* @return
*/
private byte[] decrypt(String key, byte[] bytes, Options options) {
try {
if (bytes != null) {
Cipher cipher = Cipher.getInstance(CIPHER_MODE);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key, options), new SecureRandom());
return cipher.doFinal(bytes);
}
} catch (Exception ex) {
}
return bytes;
}
/**
* 获取SecretKeySpec对象
*
* @param key
* @param options
* @return
*/
private SecretKey getSecretKey(String key, Options options) {
try {
final String lastKey = patchKey(key, options.bit);
byte[] data = lastKey.getBytes(options.encoding);
return SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(data));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
// 具体的RSA加密类
public class RsaEncrypt extends Encrypt {
// 加密模式
private static final String CIPHER_MODE = "RSA/None/PKCS1Padding";
public RsaEncrypt() {
super();
}
@Override
public String encryptString(String key, String data) {
return encrypt(getRSAPublicKey(key), data, mOptions);
}
@Override
public String decryptString(String key, String data) {
return decrypt(getRSAPrivateKey(key), data, mOptions);
}
@Override
public String encryptString(String key, String data, EncryptFactory.Options options) {
return encrypt(getRSAPublicKey(key), data, options);
}
@Override
public String decryptString(String key, String data, EncryptFactory.Options options) {
return decrypt(getRSAPrivateKey(key), data, options);
}
/**
* 随机生成RSA密钥对
* 密钥长度,范围:512~2048
*
* @param keyLength
* @return
*/
public KeyPair generateRSAKeyPair(int keyLength) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(keyLength);
return kpg.genKeyPair();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 加密字符串
*
* @param key
* @param data
* @param options
* @return
*/
private String encrypt(RSAPublicKey key, String data, Options options) {
try {
if (!TextUtils.isEmpty(data) && key != null) {
byte[] bytes = data.getBytes(options.encoding);
bytes = encrypt(key, bytes);
if (bytes != null) {
switch (options.output) {
case HEX:
return byteToHex(bytes);
case BASE64:
return byteToBase64(bytes);
default:
return new String(bytes, options.encoding);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
/**
* 加密字节数组
*
* @param key
* @param bytes
* @return
*/
private byte[] encrypt(RSAPublicKey key, byte[] bytes) {
try {
if (bytes != null && key != null) {
Cipher cipher = Cipher.getInstance(CIPHER_MODE);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
/**
* 解密字符串
*
* @param key
* @param data
* @param options
* @return
*/
private String decrypt(RSAPrivateKey key, String data, Options options) {
try {
if (!TextUtils.isEmpty(data) && key != null) {
byte[] bytes;
switch (options.output) {
case HEX:
bytes = hexToByte(data);
break;
case BASE64:
bytes = base64ToByte(data);
break;
default:
bytes = data.getBytes();
break;
}
bytes = decrypt(key, bytes);
if (bytes != null) {
return new String(bytes, options.encoding);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
/**
* 解密字节数组
*
* @param key
* @param bytes
* @return
*/
private byte[] decrypt(RSAPrivateKey key, byte[] bytes) {
try {
if (bytes != null && key != null) {
Cipher cipher = Cipher.getInstance(CIPHER_MODE);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
/**
* 获取公钥
*
* @param key
* @return
*/
private RSAPublicKey getRSAPublicKey(String key) {
try {
byte[] data = Base64.decode(key, Base64.DEFAULT);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(data);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取私钥
*
* @param key
* @return
*/
private RSAPrivateKey getRSAPrivateKey(String key) {
try {
byte[] data = Base64.decode(key, Base64.DEFAULT);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
// 加密工厂
public class EncryptFactory {
/**
* 创建一个加密类
*
* @param type
* @return
*/
public static Encrypt create(Encrypt.EncryptType type) {
Encrypt encrypt = null;
switch (type) {
case AES:
encrypt = new AesEncrypt();
break;
case DES:
encrypt = new DesEncrypt();
break;
case DES3:
encrypt = new Des3Encrypt();
break;
case RSA:
encrypt = new RsaEncrypt();
break;
}
return encrypt;
}
public static class Options {
// 默认256
public int bit;
// 字符串编码
public String encoding;
// 输出模式
public Encrypt.OutputType output;
private Options() {
// 128、192或256bits
bit = 256;
// utf-8、gb2312、gbk或gb18030
encoding = "UTF-8";
// 16进制、base64
output = Encrypt.OutputType.HEX;
}
public static Options getDefaultOptions() {
return new Options();
}
}
}
// 通过工厂模式进行数据加密
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 可选项
EncryptFactory.Options options = EncryptFactory.Options.getDefaultOptions();
options.bit = bit;
options.encoding = encoding;
options.output = output;
// 加密数据
String result = EncryptFactory.create(encryptType).encryptString("秘钥", "明文数据", options);
}
}
装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有类的一个包装。装饰器模式有效的避免了使用类的继承方式去扩展对象功能,子类无限扩张的问题,同时被装饰者与装饰者解耦,被装饰者可以不知道装饰者的存在,同时新增功能时原有代码也无需改变,符合开闭原则。但是,如果装饰层过多的话,维护起来也比较困难,如果要修改抽象组件这个基类的话,后面的一些子类可能也需要跟着一起被修改。装饰器模式通常有这么几个角色,抽象组件类、组件基础的具体实现类(被装饰者)、抽象装饰类(装饰者)、以及抽象装饰者的各个具体实现类。
下面以加解密项目为例,通过装饰器模式,实现在原有加/解密的功能基础上再次进其他的加/解密。首先定义一个抽象组件类,然后再定义一个装饰者类和被装饰者类,以及抽象装饰者的各个具体实现类。
代码示例:
/**
* 先定义一个抽象组件类
* 抽象组件类(基本的功能:加密和解密字符串)
*/
public abstract class Cipher {
// 加密字符串
public abstract String encryptString(String key, String data);
// 解密字符串
public abstract String decryptString(String key, String data);
}
// 被装饰者
/**
* 组件基础的具体实现类(被装饰者),继承Cipher类,并且具体实现加密和解密功能
* 最原始的基础加/解密方式采用:DES3加/解密的方式
*/
public class CipherConcrete extends Cipher {
@Override
public String encryptString(String key, String data) {
// 进行加密字符串 (原始加密)
try {
byte[] bytes = data.getBytes("UTF-8");
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("desede/CBC/PKCS5Padding");
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE,
SecretKeyFactory.getInstance("desede").generateSecret(new DESedeKeySpec(key.getBytes("UTF-8"))),
new IvParameterSpec(new byte[cipher.getBlockSize()]));
bytes = cipher.doFinal(bytes);
data = Base64.encodeToString(bytes, Base64.DEFAULT);
} catch (Exception ex) {
}
return data;
}
@Override
public String decryptString(String key, String data) {
// 进行解密字符串 (原始解密)
try {
byte[] bytes = Base64.decode(data, Base64.DEFAULT);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("desede/CBC/PKCS5Padding");
cipher.init(javax.crypto.Cipher.DECRYPT_MODE,
SecretKeyFactory.getInstance("desede").generateSecret(new DESedeKeySpec(key.getBytes("UTF-8"))),
new IvParameterSpec(new byte[cipher.getBlockSize()]));
bytes = cipher.doFinal(bytes);
data = new String(bytes, "UTF-8");
} catch (Exception ex) {
}
return data;
}
}
/**
* 抽象装饰类(装饰者),并且拥有一个“抽象组件”的实例
*/
public abstract class CipherDecorator extends Cipher {
// 定义一个抽象角色
private Cipher cipher;
public CipherDecorator(Cipher cipher) {
this.cipher = cipher;
}
@Override
public String encryptString(String key, String data) {
// 通过传入的Cipher对象进行加密字符串
return cipher.encryptString(key, data);
}
@Override
public String decryptString(String key, String data) {
// 通过传入的Cipher对象进行解密字符串
return cipher.decryptString(key, data);
}
}
/**
* 抽象装饰者的具体实现类(在原有的数据基础上进行AES加密或解密)
*/
public class AesCipher extends CipherDecorator {
public AesCipher(Cipher component) {
super(component);
}
@Override
public String encryptString(String key, String data) {
// 调用父类的加密方法并返回数据
String result = super.encryptString(key, data);
// 在原有数据的基础上进行AES加密
try {
byte[] bytes = result.getBytes("UTF-8");
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE,
new SecretKeySpec(key.getBytes("UTF-8"), "AES"),
new IvParameterSpec(new byte[cipher.getBlockSize()]));
bytes = cipher.doFinal(bytes);
result = Base64.encodeToString(bytes, Base64.DEFAULT);
} catch (Exception ex) {
}
return result;
}
@Override
public String decryptString(String key, String data) {
String result = "";
// 在原有数据的基础上进行AES解密
try {
byte[] bytes = Base64.decode(data, Base64.DEFAULT);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(javax.crypto.Cipher.DECRYPT_MODE,
new SecretKeySpec(key.getBytes("UTF-8"), "AES"),
new IvParameterSpec(new byte[cipher.getBlockSize()]));
bytes = cipher.doFinal(bytes);
result = new String(bytes, "UTF-8");
} catch (Exception ex) {
}
// 调用父类的解密方法并返回数据
return super.decryptString(key, result);
}
}
/**
* 抽象装饰者的具体实现类(在原有的数据基础上进行DES加密或解密)
*/
public class DesCipher extends CipherDecorator {
public DesCipher(Cipher component) {
super(component);
}
@Override
public String encryptString(String key, String data) {
// 调用父类的加密方法并返回数据
String result = super.encryptString(key, data);
// 在原有数据的基础上进行AES加密
try {
byte[] bytes = result.getBytes("UTF-8");
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("DES");
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE,
SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(key.getBytes("UTF-8"))),
new SecureRandom());
bytes = cipher.doFinal(bytes);
result = Base64.encodeToString(bytes, Base64.DEFAULT);
} catch (Exception ex) {
}
return result;
}
@Override
public String decryptString(String key, String data) {
String result = "";
// 在原有数据的基础上进行AES解密
try {
byte[] bytes = Base64.decode(data, Base64.DEFAULT);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("DES");
cipher.init(javax.crypto.Cipher.DECRYPT_MODE,
SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(key.getBytes("UTF-8"))),
new SecureRandom());
bytes = cipher.doFinal(bytes);
result = new String(bytes, "UTF-8");
} catch (Exception ex) {
}
// 调用父类的解密方法并返回数据
return super.decryptString(key, result);
}
}
// 客户端调用
public class MainActivity extends AppCompatActivity {
// 秘钥
private final static String KEY = getMd5Key("abc123456");
// 原始明文数据
private final static String ORIGINAL_DATA = "数数数数数数数数数数数数数数数数数数数数数数数数数数";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("TAG", "秘 钥:" + KEY);
Log.e("TAG", "原始数据:" + ORIGINAL_DATA);
printLine();
methodOne();
printLine();
methodTwo();
}
/**
* 方法一:
*/
private void methodOne() {
Log.e("TAG", "方法一:");
String strEncrypt;
String strDecrypt;
// 基础(3DES)加/解密 (被装饰者)
CipherConcrete concreteComponent = new CipherConcrete();
strEncrypt = concreteComponent.encryptString(KEY, ORIGINAL_DATA);
strDecrypt = concreteComponent.decryptString(KEY, strEncrypt);
Log.e("TAG", "原始加密:" + strEncrypt);
Log.e("TAG", "原始解密:" + strDecrypt);
// 装饰者的具体实现类 (AES加密类) ,如果只想在原有加密基础上再进行AES加密
AesCipher aesCipher = new AesCipher(concreteComponent);
strEncrypt = aesCipher.encryptString(KEY, ORIGINAL_DATA);
strDecrypt = aesCipher.decryptString(KEY, strEncrypt);
Log.e("TAG", "在原始加密的基础上进行AES加密:" + strEncrypt);
Log.e("TAG", "在原始解密的基础上进行AES解密:" + strDecrypt);
// 装饰者的具体实现类 (DES加密类),如果只想在原有加密基础上再进行DES加密
DesCipher desCipher = new DesCipher(concreteComponent);
strEncrypt = desCipher.encryptString(KEY, ORIGINAL_DATA);
strDecrypt = desCipher.decryptString(KEY, strEncrypt);
Log.e("TAG", "在原始加密的基础上进行DES加密:" + strEncrypt);
Log.e("TAG", "在原始解密的基础上进行DES解密:" + strDecrypt);
}
/**
* 方法二:
*/
private void methodTwo() {
Log.e("TAG", "方法二:");
// 如果想在原有加密基础上,再进行AES和DES两道加密
DesCipher desCipher = new DesCipher(new AesCipher(new CipherConcrete()));
String strEncrypt = desCipher.encryptString(KEY, ORIGINAL_DATA);
Log.e("TAG", "经过原始加密→AES加密→DES加密:" + strEncrypt);
String strDecrypt = desCipher.decryptString(KEY, strEncrypt);
Log.e("TAG", "结果DES解密→AES解密→原始解密:" + strDecrypt);
}
/**
* 换行,打印分割线
*/
private void printLine() {
for (int i = 0; i < 3; i++) {
Log.e("TAG", "-------------------------- 分割线 --------------------------");
}
}
/**
* 获取MD5加密过的KEY
*
* @param key
* @return
*/
private static String getMd5Key(String key) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
byte[] bytes = messageDigest.digest(key.getBytes());
StringBuilder builder = new StringBuilder();
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
builder.append(temp);
}
return builder.toString();
} catch (Exception e) {
e.printStackTrace();
}
return key;
}
}
中介者模式(Mediator Pattern)定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
中介者模式的特点:
在以下情况下可以使用中介者模式:
代码示例:
public interface OnSendMessage {
void onSendMessage(Sender sender, String content);
}
public class ChatRoom implements OnSendMessage {
@Override
public void onSendMessage(com.android.designpatterns.mediator.Sender sender, String content) {
System.out.println(sender.getName() + ":" + content);
}
}
public class Sender {
private String name;
private OnSendMessage onSendMessage;
Sender(String name, OnSendMessage onSendMessage) {
this.name = name;
this.onSendMessage = onSendMessage;
}
public String getName() {
return name;
}
public void sendMessage(String message) {
onSendMessage.onSendMessage(this, message);
}
}
void onMain() {
OnSendMessage group = new ChatRoom();
Sender gy = new Sender("关羽", group);
Sender zf = new Sender("张飞", group);
gy.sendMessage("二哥,好久不见!");
zf.sendMessage("三弟,大哥何在?");
}
代理模式(Proxy Pattern)定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
类的增强可以通过继承来实现,方法的增强可以通过代理来实现
代码示例:
public interface Behavior {
void onSay();
}
public class Person implements Behavior {
@Override
public void onSay() {
System.out.println("哈哈哈哈哈哈");
}
}
public class PersonProxy implements Behavior {
private Person person;
public PersonProxy(Person person) {
this.person = person;
}
@Override
public void onSay() {
before();
this.person.onSay();
after();
}
private void before() {
System.out.println("我有句话要说");
}
private void after() {
System.out.println("好了,我说完了");
}
}
void onMain(){
Person person = new Person();
Behavior behavior = new PersonProxy(person);
behavior.onSay();
}
观察者模式(Observer Pattern)定义:它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。 这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
代码示例:
public abstract class HouseObserver {
public abstract void update(House house);
}
public class House {
private String title;
private boolean favorite;
private long updateTime;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isFavorite() {
return favorite;
}
public void setFavorite(boolean favorite) {
this.favorite = favorite;
}
public long getUpdateTime() {
return updateTime;
}
public void setUpdateTime(long updateTime) {
this.updateTime = updateTime;
}
private List<HouseObserver> observers = new ArrayList<>();
public void addHouseObserver(HouseObserver observer) {
observers.add(observer);
}
public void removeHouseObserver(HouseObserver observer) {
if (observers.contains(observer)) {
observers.remove(observer);
}
}
public void notifyAllObservers() {
for (HouseObserver observer : observers) {
observer.update(this);
}
}
}
public class DetailHeadUI extends HouseObserver {
@Override
public void update(House house) {
System.out.println("DetailHeadUI-update:\n标题:" + house.getTitle() + "\n收藏状态:" + house.isFavorite() + "\n更新时间:" + house.getUpdateTime());
}
}
public class DetailBodyUI extends HouseObserver {
@Override
public void update(House house) {
System.out.println("DetailBodyUI-update:\n标题:" + house.getTitle() + "\n收藏状态:" + house.isFavorite() + "\n更新时间:" + house.getUpdateTime());
}
}
public class DetailFootUI extends HouseObserver {
@Override
public void update(House house) {
System.out.println("DetailFootUI-update:\n标题:" + house.getTitle() + "\n收藏状态:" + house.isFavorite() + "\n更新时间:" + house.getUpdateTime());
}
}
private House mHouse;
private DetailHeadUI mHeadUI;
private DetailBodyUI mBodyUI;
private DetailFootUI mFootUI;
void onMain() {
mHouse = new House();
mHeadUI = new DetailHeadUI();
mBodyUI = new DetailBodyUI();
mFootUI = new DetailFootUI();
mHouse.addHouseObserver(mHeadUI);
mHouse.addHouseObserver(mBodyUI);
mHouse.addHouseObserver(mFootUI);
mHouse.notifyAllObservers();
}
public void test1() {
mHouse.setTitle("标题1");
mHouse.setFavorite(true);
mHouse.setUpdateTime(System.currentTimeMillis());
mHouse.notifyAllObservers();
}
public void test2() {
mHouse.removeHouseObserver(mHeadUI);
mHouse.removeHouseObserver(mBodyUI);
mHouse.setTitle("标题2");
mHouse.setFavorite(true);
mHouse.setUpdateTime(System.currentTimeMillis());
mHouse.notifyAllObservers();
}
适配器模式(Adapter Pattern)定义:把一种接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
Adapter 类继承Adaptee (被适配类),同时实现Target 接口(因为 Java 不支持多继承,所以只能通过接口的方法来实现多继承),在 Client 类中我们可以根据需要选择并创建任一种符合需求的子类,来实现具体功能。
由于适配器类是适配者类的子类,因此可以再适配器类中置换一些适配者的方法,使得适配器的灵活性更强;但是对于Java、C#等不支持多继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为接口,不能为类,其使用有一定的局限性,不能将一个适配者类和他的子类同时适配到目标接口。
代码示例:
public interface Target {
void onSomething();
}
public class Adaptee {
public void doSomething() {
System.out.println("doSomething...");
}
}
public class Adapter extends Adaptee implements Target {
@Override
public void onSomething() {
super.doSomething();
}
}
void onMain(){
Target target = new Adapter();
target.onSomething();
}
享元模式(Flyweight Pattern)定义:主要用于减少创建对象的数量,以减少内存占用和提高性能。
代码示例:
// 享元工厂
public class CipherFactory {
// “加密类”容器池
private final static HashMap<String, Cipher> pool = new HashMap<>();
public static Cipher create(String type) {
// 加密的抽象类(抽象享元角色),抽象类不依赖于具体的实现类
Cipher cipher = null;
if (pool.containsKey(type)) {
// 从容器池中获取对象,大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能
cipher = pool.get(type);
} else {
switch (type) {
case "AES":
// 具体的AES加密类(具体的享元角色),具体的实现类依赖于抽象类
cipher = new AesCipher();
break;
case "DES":
// 具体的DES加密类(具体的享元角色),具体的实现类依赖于抽象类
cipher = new DesCipher();
break;
}
pool.put(type, cipher);
}
return cipher;
}
}
public abstract class Cipher {
public abstract String encryptString(String key, String data);
public abstract String decryptString(String key, String data);
}
public class AesCipher extends Cipher {
public AesCipher() {
System.out.println("AesCipher构造函数...");
}
@Override
public String encryptString(String key, String data) {
return "加密秘钥:" + key + "\n" + "加密数据" + data + "\n" + "我已实现了AES的具体加密方法,并返回加密后的数据:";
}
@Override
public String decryptString(String key, String data) {
return "解密秘钥:" + key + "\n" + "解密数据" + data + "\n" + "我已实现了AES的具体解密方法,并返回解密后的数据:";
}
}
public class DesCipher extends Cipher {
public DesCipher() {
System.out.println("DesCipher构造函数...");
}
@Override
public String encryptString(String key, String data) {
return "加密秘钥:" + key + "\n" + "加密数据" + data + "\n" + "我已实现了DES的具体加密方法,并返回加密后的数据:";
}
@Override
public String decryptString(String key, String data) {
return "解密秘钥:" + key + "\n" + "解密数据" + data + "\n" + "我已实现了DES的具体解密方法,并返回解密后的数据:";
}
}
public class MainActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
onMain();
}
void onMain() {
final String key = "123456";
// 通过循环20次来测试在“享元模式”下减少创建对象的数量
for (int i = 0; i < 20; i++) {
String data = CipherFactory.create("AES").encryptString(key, "哈哈哈哈哈哈哈哈哈哈哈");
System.out.println(data);
data = CipherFactory.create("AES").decryptString(key, data);
System.out.println(data);
data = CipherFactory.create("DES").encryptString(key, "哈哈哈哈哈哈哈哈哈哈哈");
System.out.println(data);
data = CipherFactory.create("DES").decryptString(key, data);
System.out.println(data);
}
}
}
组合模式(Composite Pattern)定义:是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
下面给出一则需求,已知游戏规则:
“红红肉” 可以通过 “精品猪肉+井水” 组合而成;
“五花肉” 可以通过 “精品猪肉+杏仁” 组合而成;
“可乐鸡翅” 可以通过 “鸡翅+井水” 组合而成;
“一飞冲天” 可以通过 “鸡翅+肉桂” 组合而成;
请根据给定的游戏规则,通过组合模式实现业务需求逻辑
代码示例:
public interface OnSynthesis {
// 添加材料
void addMaterial(Material material);
// 移除材料
void removeMaterial(Material material);
// 合成食物
Food onSynthesis();
}
public class Food {
// 食物名称
private String name;
// 食物价格
private float price;
// 食物描述
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
/**
* 抽象的材料类
*/
public abstract class Material {
// 材料集合
private List<Material> list = new ArrayList<>();
public Material() {
list.add(this);
}
// 材料的名称
public abstract String name();
// 材料价格
public abstract float price();
public void addMaterial(Material material) {
list.add(material);
}
public void removeMaterial(Material material) {
list.remove(material);
}
public Food onSynthesis() {
/**
* 合成规则:
* “红红肉” 由 “精品猪肉+井水” 组合而成
* “五花肉” 由 “精品猪肉+杏仁” 组合而成
* “可乐鸡翅” 由 “鸡翅+井水” 组合而成
* “一飞冲天” 由 “鸡翅+肉桂” 组合而成
*/
if (list.size() > 2) {
Food food = new Food();
food.setName("合成失败");
food.setPrice(0);
food.setDescription("非法合成,食材已超过了两种,请遵循合成的游戏规则!");
return food;
}
float price = 0;
List<String> names = new ArrayList<>();
for (Material material : list) {
price = material.price() + price;
names.add(material.name());
}
// 自定义合成规则,案例中根据材料名称来合成食物
Food food = new Food();
food.setPrice(price);
if (names.contains("精品猪肉") && names.contains("井水")) {
// 红红肉
food.setName("红红肉");
food.setDescription("传说吃了它的人就一定能红,能在5分钟内每3秒恢复一定的生命");
} else if (names.contains("精品猪肉") && names.contains("杏仁")) {
food.setName("五花肉");
food.setDescription("因为做出的肉形状优雅,神似五朵金花,所以人称五花肉,吃了之后可以回复600点生命");
} else if (names.contains("鸡翅") && names.contains("井水")) {
food.setName("可乐鸡翅");
food.setDescription("可以用来演奏音乐的鸡翅,让人身心愉快,10分钟内移动速度明显变快了");
} else if (names.contains("鸡翅") && names.contains("肉桂")) {
food.setName("一飞冲天");
food.setDescription("人们总是认为吃鸡翅有助于改善身手不敏捷的状况,自己相信了,移动自然就快了,10分钟内有效");
} else {
food.setName("合成失败" + names.toString());
food.setPrice(0);
food.setDescription("非法合成,组合的食材不合规则,请遵循合成的游戏规则!");
}
return food;
}
}
public class Almonds extends Material implements OnSynthesis {
@Override
public String name() {
return "杏仁";
}
@Override
public float price() {
return 800;
}
@Override
public void addMaterial(Material material) {
super.addMaterial(material);
}
@Override
public void removeMaterial(Material material) {
super.removeMaterial(material);
}
@Override
public Food onSynthesis() {
return super.onSynthesis();
}
}
public class ChickenWings extends Material implements OnSynthesis {
@Override
public String name() {
return "鸡翅";
}
@Override
public float price() {
return 200;
}
@Override
public void addMaterial(Material material) {
super.addMaterial(material);
}
@Override
public void removeMaterial(Material material) {
super.removeMaterial(material);
}
@Override
public Food onSynthesis() {
return super.onSynthesis();
}
}
public class Cinnamon extends Material implements OnSynthesis {
@Override
public String name() {
return "肉桂";
}
@Override
public float price() {
return 600;
}
@Override
public void addMaterial(Material material) {
super.addMaterial(material);
}
@Override
public void removeMaterial(Material material) {
super.removeMaterial(material);
}
@Override
public Food onSynthesis() {
return super.onSynthesis();
}
}
public class FinePork extends Material implements OnSynthesis {
@Override
public String name() {
return "精品猪肉";
}
@Override
public float price() {
return 400;
}
@Override
public void addMaterial(Material material) {
super.addMaterial(material);
}
@Override
public void removeMaterial(Material material) {
super.removeMaterial(material);
}
@Override
public Food onSynthesis() {
return super.onSynthesis();
}
}
public class WellWater extends Material implements OnSynthesis {
@Override
public String name() {
return "井水";
}
@Override
public float price() {
return 100;
}
@Override
public void addMaterial(Material material) {
super.addMaterial(material);
}
@Override
public void removeMaterial(Material material) {
super.removeMaterial(material);
}
@Override
public Food onSynthesis() {
return super.onSynthesis();
}
}
public class MainActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
onMain();
}
void onMain() {
// 杏仁
Almonds almonds = new Almonds();
// 鸡翅
ChickenWings chickenWings = new ChickenWings();
// 肉桂
Cinnamon cinnamon = new Cinnamon();
// 精品猪肉
FinePork finePork = new FinePork();
// 井水
WellWater wellWater = new WellWater();
Food food;
// 做红红肉,精品猪肉 + 井水
finePork.addMaterial(wellWater);
food = finePork.onSynthesis();
logOutput(food);
// 做五花肉,精品猪肉 + 杏仁 (先移除井水)
finePork.removeMaterial(wellWater);
finePork.addMaterial(almonds);
food = finePork.onSynthesis();
logOutput(food);
// 做可乐鸡翅,鸡翅 + 井水
chickenWings.addMaterial(wellWater);
food = chickenWings.onSynthesis();
logOutput(food);
// 做一飞冲天,鸡翅 + 肉桂 (先移除井水)
chickenWings.removeMaterial(wellWater);
chickenWings.addMaterial(cinnamon);
food = chickenWings.onSynthesis();
logOutput(food);
}
private void logOutput(Food food) {
Log.d("TAG", "食物名称:" + food.getName() + " 食物价格:" + ((int) food.getPrice()) + "游戏币 食物描述:" + food.getDescription());
}
}