设计模式的优点
合理的使用设计模式来开发程序,可以有效地提高代码的复用性,可维护性,灵活性,扩展性。
简单工厂模式
实现一个计算器,可以进行±*/运算。用工厂来生成相应的计算对象。
//主类
package com.sea;
import java.util.Scanner;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
public class Calculator {
public static void main(String[] args) {
Operation operation;
Scanner input = new Scanner(System.in);
System.out.println("请输入你要进行的运算方式(+-*/)");
String symbol = input.next();
operation = OperationFactory.creatOperation(symbol);
System.out.println("输入运算数");
double numA = input.nextDouble();
double numB = input.nextDouble();
try {
double result = operation.getResult(numA, numB);
System.out.println("result = "+result);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
//计算对象类 其中Operation为父类,里面定义了计算数和一个getResult方法。其他子类来实现这个方法。(继承)
package com.sea;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
public abstract class Operation {
private double numA;
private double numB;
public abstract double getResult(double numA,double numB) throws Exception;
public double getNumA() {
return numA;
}
public void setNumA(double numA) {
this.numA = numA;
}
public double getNumB() {
return numB;
}
public void setNumB(double numB) {
this.numB = numB;
}
}
class OperationAdd extends Operation{
@Override
public double getResult(double numA, double numB) {
return numA+numB;
}
}
class OperationSubtraction extends Operation{
@Override
public double getResult(double numA, double numB) {
return numA-numB;
}
}
class OperationMultiplication extends Operation{
@Override
public double getResult(double numA, double numB) {
return numA*numB;
}
}
class OperationDivision extends Operation{
@Override
public double getResult(double numA, double numB) throws Exception {
if(numB==0)
throw new Exception("除数不能为0");
return numA/numB;
}
}
//工厂类,根据输入的符号来生成相应的对象。(多态)
package com.sea;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
public class OperationFactory {
public static Operation creatOperation(String symbol){
Operation operation = null;
switch (symbol){
case "+" :
operation = new OperationAdd();
break;
case "-" :
operation = new OperationSubtraction();
break;
case "*" :
operation = new OperationMultiplication();
break;
case "/" :
operation = new OperationDivision();
break;
}
return operation;
}
}
工厂模式可以将一些具有相同父类的对象的创建过程集中到一起。将对象的创建和使用分隔开。大大增加了程序可扩展性并且更加利于维护。当你需要更改/添加对象的实现类时,只需要更改工厂即可。而不必去每一个用到该对象的地方做修改。
策略模式
实现一个商场收银台功能,当商场进行不同的促销活动时,将商品价格转换成实际要支付的价格。
策略模式:它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
package com.sea;
import java.util.Scanner;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
//收银台主类
public class Cashier {
public static void main(String[] args) {
PayMoneyContext context = null;
System.out.println("选择销售策略");
System.out.println("1.正常出售");
System.out.println("2.打8折出售");
System.out.println("3.满500返200");
Scanner input = new Scanner(System.in);
int type = input.nextInt();
context = new PayMoneyContext(type);
System.out.println("输入购买商品总价值");
double money = input.nextDouble();
System.out.println("实际需要支付:"+context.getResult(money));
}
}
package com.sea;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
//付钱算法父类
public abstract class PayMoney {
public abstract double payMoneyAlgorithm(Double money) ;
}
//正常的付钱算法
class NormalAlgorithm extends PayMoney{
@Override
public double payMoneyAlgorithm(Double money) {
return money;
}
}
//打折付钱算法
class DiscountAlgorithm extends PayMoney{
private double proportion = 1;
public DiscountAlgorithm(double proportion){
this.proportion = proportion;
}
@Override
public double payMoneyAlgorithm(Double money) {
return money*proportion;
}
}
//返利付钱算法
class RebateAlgorithm extends PayMoney{
private double critical = Double.MAX_VALUE;//临界值,到达这个值才会返利
private double rebate = 0;
public RebateAlgorithm(double critical,double rebate){
this.critical = critical;
this.rebate = rebate;
}
@Override
public double payMoneyAlgorithm(Double money) {
if(money>=critical){
return money-rebate;
}else
return money;
}
}
package com.sea;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
//类略类
public class PayMoneyContext {
private PayMoney payMoney = null;
public PayMoneyContext(int type){
switch (type){
case 1://1.正常出售
payMoney = new NormalAlgorithm();
break;
case 2://2.打8折出售
payMoney = new DiscountAlgorithm(0.8);
break;
case 3://3.满500返200
payMoney = new RebateAlgorithm(500,200);
}
}
public double getResult(double money){
return payMoney.payMoneyAlgorithm(money);
}
}
策略模式与工厂模式在结构上有点类似。不过工厂类只负责生产对象,具体的方法调用还需要调用者进行调用。并且调用者需要既知道工厂类,也需要认识工厂创建的实例。而策略模式中,调用者只需要认识策略类即可,甚至都不需要知道具体是哪个类调用的业务方法。在策略类中可以用简单工厂模式生成对象,并在对调用者开放的方法中实现具体对象的方法调用,而不在需要调用者再去主动调用。再一次降低了耦合度。
单一职责原则
单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。
如果一个类承担过多的责任,那么就相当于这些功能高度耦合在一起。当更改其中一个功能时,可能导致其他正常运行的功能发生不可预知的错误。单一职责原则是高内聚低耦合的体现。
开放——封闭原则
开放——封闭原则是说软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。
这就需要我们对功能做抽象处理。比如,一块木板能用来干什么呢?可以用来制作桌子,椅子,床等等。如果不适用开放——封闭原则,我们会怎么做呢?
最开始木板只能用来制作桌子。
public interface BoardInterface {
void makingTable();
}
public class Board implements BoardInterface {
@Override
public void makingTable() {
System.out.println("制作桌子的流程");
}
}
此时如果要增加新的需求怎么办呢?直接在接口中添加方法,然后再在实现类中实现方法不就行了么?但是这样写的代码既不灵活,难以维护,不好扩展,复用性差。这样写就完全不符合开放——封闭原则。增加需求要尽量用增加代码来解决(增加类)而不是修改之前的类。要尽量做到类一旦设计好就不再更改。因此应该改为
package com.sea;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
public interface BoardInterface {
void making();
}
package com.sea;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
public class BedBoard implements BoardInterface {
@Override
public void making() {
System.out.println("制作床的流程");
}
}
package com.sea;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
public class CharBoard implements BoardInterface {
@Override
public void making() {
System.out.println("制作椅子的流程");
}
}
package com.sea;
/**
* @Auther: Maple
* @Date: 2020/10/15
*/
public class TableBoard implements BoardInterface {
@Override
public void making() {
System.out.println("制作桌子的流程");
}
}
如果需要为这个木板增加新的业务,只需要添加新的类即可。
里氏代换原则
里氏代换缓则:子类型必须能够替换掉他们的父类型。
如果此时有一个动物类,他里面有跑 跳 吃 喝方法。那么当要设计一个鱼类时能不能继承这个动物类呢。根据里氏代换原则是不能的。因为鱼并不能跑与跳。因此子类并不能够替换掉他们的父类。
依赖倒转原则
高层模块不应该依赖底层模块。两个都应该依赖抽象。
抽象不应该依赖细节。细节应该依赖抽象。
高层模块如果直接依赖底层模块的话,如果要更换底层模块,那么即使高层模块的逻辑不需要改变,高层模块也不能复用了。这显然不是我们想要的。
如果高层模块与底层模块都是依赖于接口的就不同了。高层模块只关心接口包含哪些功能,而不必关心具体实现细节。底层模块只需要实现这个接口便可以与高层模块间接合作。这样当需要更换底层模块时,只需要找另一个实现了这个接口的模块替换即可,而不必再更改高层模块。
装饰模式
装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
当没有用装饰模式时。要为一个类的功能添加某种修饰的时候,可以通过在类中添加方法,字段,逻辑的方式来实现。如果新加入的这些功能在某些条件下才会执行。这就使得需要在类中添加很多的逻辑判断。这无疑使类变得更加复杂。
如果使用装饰模式,就不会有这些顾虑。独立出一个个的装饰类,装饰类中只需要完成相应的装饰逻辑,而不用考虑如何调用。当要对类进行装饰时,只需要调用者按照一定顺序使用装饰类即可;
例子:
//实现功能的类
public class Animal {
private String name;
public Animal(){
}
public Animal(String name){
this.name = name;
}
public void show(){
System.out.println("的"+name);
}
}
//装饰类
class Tail extends Body{
@Override
public void show(){
System.out.print(" 一条长尾巴 ");
super.show();
}
}
class Ears extends Body{
@Override
public void show(){
System.out.print(" 两个大耳朵 ");
super.show();
}
}
class Wings extends Body{
@Override
public void show(){
System.out.print(" 一双翅膀 ");
super.show();
}
}
class Eyes extends Body{
@Override
public void show(){
System.out.print(" 一只眼睛 ");
super.show();
}
}
class Nose extends Body{
@Override
public void show(){
System.out.print(" 一个鼻子 ");
super.show();
}
}
//用来扩展Animal的功能
public class Body extends Animal {
Animal animal;
public void decorate(Animal animal) {
this.animal = animal;
}
@Override
public void show(){
if(animal!=null){
animal.show();
}
}
}
public class Test1 {
public static void main(String[] args) {
Animal animal = new Animal("兔子");
Tail tail = new Tail();
Ears ears = new Ears();
Eyes eyes = new Eyes();
Wings wings = new Wings();
tail.decorate(animal);
ears.decorate(tail);
eyes.decorate(ears);
wings.decorate(eyes);
System.out.print("这是一只拥有");
wings.show();
}
}
执行结果
代理模式
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
代理模式可以隔离客户类和业务实现类。在他俩中间加入一层代理。代理模式可以在委托类的方法实现的前后加入一公共的扩展内容。而不必打开委托类。这也符合开闭原则。
例子
//功能的接口(网购)
public interface OnlineShopping {
public void buyApple();
}
//委托类(顾客)
public class Client implements OnlineShopping{
@Override
public void buyApple() {
System.out.println("挑选苹果");
}
}
//代理类
public class Proxy implements OnlineShopping {
Client client;
@Override
public void buyApple() {
//真正方法执行前加入一些扩展
System.out.println("提供网购APP");
if(client==null){
client = new Client();
}
client.buyApple();
//真正方法执行后加入一些扩展
System.out.println("将商品送到顾客家中")