一(单一职责)段历史(里氏代换),不能被低迷(迪米特)的人所开(开闭原则)辟,因为他们太依赖(依赖倒转)反复(合成复用)去用借口(接口隔离)逃避。
定义:一个类而言,应该只有一个引起它变化的原因
案例: 比如咱们写个订单模块和用户模块,都是分别创建了2个类,一个是orderController和userController,这里就体现了单一职责原则。总不可能所有的controller 都在写在一起呀。
总结:分别功能的不同,写不同类
定义:软件实体应尽量在不修改原有代码的情况下进行扩展
案例:这里的支付,如果接受参数改为类的话,可能要要根据新类的出现,继续增加方法,如果该接口就可以解决这个问题
public interface Pay {
// 支付
void pay();
}
public class AliPay implements Pay {
@Override
public void pay() {
System.out.println("正在使用支付宝支付");
}
}
public class WXPay implements Pay{
@Override
public void pay() {
System.out.println("正在使用微信支付");
}
}
// 客户端调用-押金支付选择支付手段
public class DepositPay {
// 支付方式 (这边可以通过依赖注入的方式来注入)
// 支付方式可以写在配置文件中
// 现在不管你选用何种方式,我都不需要更改
@Autowired
Pay payMode;
void pay(Pay payMode){
payMode.pay();
}
}
总结:方法的参数最好改为接口的形式
定义:所有引用基类(父类的)地方都可以用子类来替换,且程序不会有任何的异常。但是反过来就不行,所有使用子类的地方则不一定能用基类来替代,很简单的例子狗是动物,不能说动物是狗,因为可能还有猫。。。。
案例:其实就是继承父类的是时候,new的时候,指定子类 Father f = new Son();
import java.util.HashMap;
public class Father {
public void func(HashMap m){
System.out.println( "执行父类..." );
}
}
import java.util.Map;
public class Son extends Father{
public void func(Map m){
//方法的形参比父类的更宽松
System.out.println( "执行子类..." );
}
}
import java.util.HashMap;
public class Client{
public static void main(String[] args) {
Father f = new Son(); //引用基类的地方能透明地使用其子类的对象。
HashMap h = new HashMap();
f.func(h);
}
}
总结:继承的父类,可以自由添加方法,声明的时候指明子类的对象
定义:抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。
案例:其实和开闭原则差不多。注意接收参数是接口
public interface Pay {
// 支付
void pay();
}
public class AliPay implements Pay {
@Override
public void pay() {
System.out.println("正在使用支付宝支付");
}
}
public class WXPay implements Pay{
@Override
public void pay() {
System.out.println("正在使用微信支付");
}
}
// 客户端调用-押金支付选择支付手段
public class DepositPay {
// 支付方式 (这边可以通过依赖注入的方式来注入)
// 支付方式可以写在配置文件中
// 现在不管你选用何种方式,我都不需要更改
@Autowired
Pay payMode;
void pay(Pay payMode){
payMode.pay();
}
}
总结:其实就是面向接口编程,接受参数变为接口即可
定义:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口,类间的依赖关系应该建立在最小的接口上
案例:其实就类似前面的讲的controller要分别定义不同的模块,接口也是, 类在继承接口的时候,要继承与最小接口
错误案例
public interface IAnimal{
/**
* 吃饭
*/
void eat();
/**
* 工作
*/
void work();
/**
* 飞行
*/
void fly();
}
public class Tony implements IAnimal{
@Override
public void eat() {
System.out.println("tony吃");
}
@Override
public void work() {
System.out.println("tony工作");
}
@Override
public void fly() {
System.out.println("tony不会飞");
}
}
public class Bird implements IAnimal{
@Override
public void eat() {
System.out.println("鸟吃");
}
@Override
public void work() {
System.out.println("鸟工作");
}
@Override
public void fly() {
System.out.println("鸟飞");
}
}
```java
正确案例
```css
/**
* 抽象动物的行为
*/
public interface IAnimal {
/**
* 吃饭
*/
void eat();
/**
* 睡觉
*/
void sleep();
}
/**
* 高级动物人 的行为
*/
public interface IAdvancedAnimalBehavior {
/**
* 打牌
*/
void playCard();
/**
* 骑车
*/
void byBike();
}
/**
* 低级动物的行为
*/
public interface IJuniorAnimalBehavior {
/**
* fly
*/
void fly();
}
/**
* 实现高级动物人的共通方法
*/
public class AbstractAdvancedAnimal implements IAnimal {
@Override
public void eat() {
System.out.println("人吃");
}
@Override
public void sleep() {
System.out.println("人睡");
}
}
/**
* 实现低级动物人的共通方法
*/
public class AbstractJuniorAnimal implements IAnimal {
@Override
public void eat() {
System.out.println("动物吃");
}
@Override
public void sleep() {
System.out.println("动物睡");
}
}
// tony
public class Tony extends AbstractAdvancedAnimal implements IAdvancedAnimalBehavior {
@Override
public void playCard() {
System.out.println("tony打牌");
}
@Override
public void byBike() {
System.out.println("tony骑车");
}
}
// 鸟
public class Bird extends AbstractJuniorAnimal implements IJuniorAnimalBehavior{
@Override
public void fly() {
System.out.println("鸟飞");
}
}
总结:每个接口都要细分开来,就类似 一个是orderController和userController
定义:尽量使用对象组合,而不是继承来达到复用的目的
案例
1.3 问题由来
汽车按“动力源”划分可分为汽油汽车、电动汽车等;按“颜色”划分可分为白色汽车、黑色汽车和红色汽车等。如果同时考虑这两种分类,其组合就有6种。将上述业务用代码实现,如果只用继承复用,那么最后有6个子类白色油车、黑色油车、红色油车、白色电动汽车、黑色电动汽车、红色电动汽车。这种情况实现方式,会导致子类过多的情况出现。 并且当增加新的“动力源”或者增加新的“颜色”都要修改源代码,这违背了开闭原则,显然不可取。
先来看一下有问题的代码。
public abstract class Car
{
abstract void run();
}
public class ElectricCar extends Car
{
@Override
void run()
{
System.out.println("电动汽车");
}
}
public class PetrolCar extends Car {
@Override
void run()
{
System.out.println("汽油汽车");
}
}
public class BlackElectricCar extends ElectricCar
{
public void appearance()
{
System.out.print("黑色");
super.run();
}
}
public class BlackPetrolCar extends PetrolCar
{
public void appearance()
{
System.out.print("黑色");
super.run();
}
}
public class RedElectricCar extends ElectricCar
{
public void appearance()
{
System.out.print("红色");
super.run();
}
}
public class RedPetrolCar extends PetrolCar
{
public void appearance()
{
System.out.print("红色");
super.run();
}
}
public class WhiteElectricCar extends ElectricCar
{
public void appearance()
{
System.out.print("白色");
super.run();
}
}
public class WhitePetrolCar extends PetrolCar
{
public void appearance()
{
System.out.print("白色");
super.run();
}
}
public class Test {
public static void main(String[] args) {
RedElectricCar redElectricCar = new RedElectricCar();
redElectricCar.appearance();//红色电动汽车
}
}
采用组合或聚合复用方式,第一步先将将颜色Color抽象为接口,有白色,黑色,红色三个颜色实现类,第二步将Color对象组合在汽车Car类中,最终我们只需要生成5个类,就可以实现上诉功能。同时当增加新的“动力源”或者增加新的“颜色,都不要修改源代码,只要增加实现类就可以。
public abstract class Car
{
abstract void run();
Color color;
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
public interface Color
{
void colorKind();
}
public class ElectricCar extends Car
{
@Override
void run()
{
System.out.println("电动汽车");
}
}
public class PetrolCar extends Car {
@Override
void run()
{
System.out.println("汽油汽车");
}
}
public class White implements Color{
@Override
public void colorKind()
{
System.out.println("白色");
}
}
public class Black implements Color{
@Override
public void colorKind()
{
System.out.println("黑色");
}
}
public class Red implements Color{
@Override
public void colorKind()
{
System.out.println("红色");
}
}
public class Test
{
public static void main(String[] args)
{
ElectricCar electricCar = new ElectricCar();
White color = new White();
electricCar.setColor(color);
electricCar.getColor().colorKind();//白色
electricCar.run();//电动汽车
}
}
总结:最好用依赖注入代替继承
一个软件实体应当尽可能少地与其他实体发生相互作用。每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位
朋友类的定义:出现在成员变量、方法的输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类
public class Jia{
private Friend friend;
public Friend getFriend() {
return friend;
}
public void setFriend(Friend friend) {
this.friend = friend;
}
public void play(Friend friend){
friend.play();
}
}
//朋友
public class Friend {
public void play(){
System.out.println("朋友");
}
public void playWithStranger() {
Stranger stranger = new Stranger();
stranger.play();
}
}
public class Stranger {
public void play(){
System.out.println("陌生人");
}
}
总结:和自己关系性不大的类,成员,有相关对象的实例。