SOLID 5原則
58705 ワード
1 SRP (Single Responsibility Principle)
一つの階級には責任がある.
SRPを適用する前に
public class Production {
private String name;
private int price;
public Production(String name, int price) {
this.name = name;
this.price = price;
}
public void updatePrice(int price) {
this.price = price;
}
}
public class ProductionUpdateService {
public void update(Production production, int price) {
//validate price
validatePrice(price);
//update price
production.updatePrice(price);
}
private void validatePrice(int price) {
if (price < 1000) {
throw new IllegalArgumentException("최소가격은 1000원 이상입니다.");
}
}
}
ProductionUpdateServiceの役割は、製品の内容を変更することです.したがって、価格の有効性を検証するValidatePrice()はProductionUpdateServiceの責任ですか?
プロペラ
価格の有効性を検証するには、製品が実際の価格を変更する責任を負う情報と見なす必要があります.これに基づいて、検証責任を製品に移行するコードは次のとおりです.
SRP適用後
public class Production {
private static final int MINIMUM_PRICE = 1000;
private String name;
private int price;
public Production(String name, int price) {
this.name = name;
this.price = price;
}
public void updatePrice(int price) {
validatePrice(price);
this.price = price;
}
private void validatePrice(int price) {
if (price < MINIMUM_PRICE) {
throw new IllegalArgumentException(String.format("최소가격은 %d원 이상입니다.", MINIMUM_PRICE));
}
}
}
public class ProductionUpdateService {
public void update(Production production, int price) {
//update price
production.updatePrice(price);
}
}
2 OCP (Open-Closed Principle)
ソフトウェア要素は拡張で開き、変更で閉じます.
OCPより前
public class Production {
private String name;
private int price;
// N(일반) ,E(전자티켓) ,L(지역상품)...
private String option;
public Production(String name, int price, String option) {
this.name = name;
this.price = price;
this.option = option;
}
public int getNameLength() {
return name.length();
}
public String getOption() {
return option;
}
}
public class ProductionValidator {
public void validateProduction(Production production) throws IllegalArgumentException {
if (production.getOption().equals("N")) {
if (production.getNameLength() < 3) {
throw new IllegalArgumentException("일반 상품의 이름은 3글자보다 길어야 합니다.");
}
} else if (production.getOption().equals("E")) {
if (production.getNameLength() < 10) {
throw new IllegalArgumentException("전자티켓 상품의 이름은 10글자보다 길어야 합니다.");
}
} else if (production.getOption().equals("L")) {
if (production.getNameLength() < 20) {
throw new IllegalArgumentException("지역 상품의 이름은 20글자보다 길어야 합니다.");
}
}
}
}
OCPの原則を適用した後
public interface Validator {
boolean support(Production production);
void validate(Production production) throws IllegalArgumentException;
}
public class DefaultValidator implements Validator {
@Override
public boolean support(Production production) {
return production.getOption().equals("N");
}
@Override
public void validate(Production production) throws IllegalArgumentException {
if (production.getNameLength() < 3) {
throw new IllegalArgumentException("일반 상품의 이름은 3글자보다 길어야 합니다.");
}
}
}
public class ETicketValidator implements Validator {
@Override
public boolean support(Production production) {
return production.getOption().equals("E");
}
@Override
public void validate(Production production) throws IllegalArgumentException {
if (production.getNameLength() < 10) {
throw new IllegalArgumentException("전자티켓 상품의 이름은 10글자보다 길어야 합니다.");
}
}
}
public class LocalValidator implements Validator {
@Override
public boolean support(Production production) {
return production.getOption().equals("L");
}
@Override
public void validate(Production production) throws IllegalArgumentException {
if (production.getNameLength() < 20) {
throw new IllegalArgumentException("지역 상품의 이름은 20글자보다 길어야 합니다.");
}
}
}
public class ProductValidator {
private final List<Validator> validators = Arrays.asList(new DefaultValidator(), new ETicketValidator(), new LocalValidator());
public void validate(Production production) {
Validator productionValidator = new DefaultValidator();
for (Validator localValidator : validators) {
if (localValidator.support(production)) {
productionValidator = localValidator;
break;
}
}
productionValidator.validate(production);
}
}
3 LSP (Liskov Substitution Principle)
LSPを適用する前に
class Rectangle {
protected _width: number = -1;
protected _height: number = -1;
public get width() {
return this._width;
}
public set width(w: number) {
this._width = w;
}
public get height() {
return this._height;
}
public set height(h: number) {
this._height = h;
}
public get area() {
return this._width * this._height;
}
}
class Square extends Rectangle {
public set width(w: number) {
this._width = w;
this._height = w;
}
public set height(h: number) {
this._width = h;
this._height = h;
}
}
const rec: Rectangle = new Rectangle();
rec.width = 3;
rec.height = 4;
console.log(rec.area === 12); // true
const rec2: Rectangle = new Square();
rec2.width = 3;
rec2.height = 4;
console.log(rec.area === 12); // false
親Rectangleでの子Squareのarea()機能が正しくありません.LSP適用後
// Shape 인터페이스는 넓이를 구할 수 있는 것(기하학 관점의 면)이라고 가정한다.
interface Shape {
readonly area: number;
}
class Rectangle implements Shape {
constructor(public width: number, public height: number) {}
public get area() {
return this.width * this.height;
}
}
class Square implements Shape {
constructor(public width: number) {}
public get area() {
return this.width ** 2;
}
}
const rec: Shape = new Rectangle(3, 4);
console.log(rec.area); // 12
const sq: Shape = new Square(4);
console.log(sq.area); // 16
4 ISP (Integration Segregation Principle)
複数の特定のクライアントインタフェースは、1つの汎用インタフェースよりも優れています.
ISPを適用する前に
public interface AllInOneDevice {
void print();
void copy();
void fax();
}
public class SmartMachine implements AllInOneDevice {
@Override
public void print() {
System.out.println("print");
}
@Override
public void copy() {
System.out.println("copy");
}
@Override
public void fax() {
System.out.println("fax");
}
}
package solid.isp.before;
public class PrinterMachine implements AllInOneDevice {
@Override
public void print() {
System.out.println("print");
}
@Override
public void copy() {
throw new UnsupportedOperationException();
}
@Override
public void fax() {
throw new UnsupportedOperationException();
}
}
印刷は上書きされていますが、他の機能を実装する必要はありませんので、Unsupported OperationExceptionが発生します.この場合、プリンタがレプリケーション機能を実装しているかどうか分からないため、インタフェースのみを知っているクライアントで予期せぬエラーが発生する可能性があります.
ISP適用後
public interface PrinterDevice {
void print();
}
public interface CopyDevice {
void copy();
}
public interface FaxDevice {
void fax();
}
public class SmartMachine implements PrinterDevice, CopyDevice, FaxDevice {
@Override
public void print() {
System.out.println("print");
}
@Override
public void copy() {
System.out.println("copy");
}
@Override
public void fax() {
System.out.println("fax");
}
}
// 구현한 객체
public class PrinterMachine implements PrinterDevice {
@Override
public void print() {
System.out.println("print");
}
}
// 클라이언트가 사용할 경우
@DisplayName("하나의 기능만을 필요로 한다면 하나의 인터페이스만 구현하도록 하자")
@Test
void singleInterface() {
PrinterDevice printer = new SmartMachine();
printer.print();
}
5 DIP (Dependency Inversion Principle)
抽象に頼るには,具体化に頼るわけにはいかない.
DIPを適用する前に
public class ProductionService {
private final LocalValidator localValidator;
public ProductionService(LocalValidator localValidator) {
this.localValidator = localValidator;
}
public void validate(Production production) {
localValidator.validate(production);
}
}
public class LocalValidator {
public void validate(Production production) {
//validate
}
}
DIP適用後
public interface Validator {
void validate(Production production);
}
public class LocalValidator implements Validator {
@Override
public void validate(Production production) {
//validate
}
}
public class ETicketValidator implements Validator {
@Override
public void validate(Production production) {
//validate
}
}
public class ProductionService {
private final Validator validator;
public ProductionService(Validator validator) {
this.validator = validator;
}
public void validate(Production production) {
validator.validate(production);
}
}
ソース
https://bottom-to-top.tistory.com/27
https://medium.com/humanscape-tech/solid-%EB%B2%95%EC%B9%99-%E4%B8%AD-lid-fb9b89e383ef
Reference
この問題について(SOLID 5原則), 我々は、より多くの情報をここで見つけました https://velog.io/@csk917work/SOLID-5-원칙テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol