SOLID
★SOLIDはオブジェクト指向による設計原則をまとめる。
S:Single Responsibility Principle 单一职责
O:Open-Closed Principle 开放封闭
L:Liskov Substitution Principle 里氏替换
I:Interface Segregation Principle 接口分离
D:Dependency Injection/Inversion Principle 依赖倒置
★SOLID以外
DRY (Don't Repeat Yourself)
Encapsulate what varies
Favour Composition over Inheritance
Programming for Interface not Implementation
Delegation Principle
・「SRP」に関するサンプル
改善前
class Employee
{
private string name;
private int id;
private double salary;
public Employee(string name, int id, double salary)
{
this.name = name;
this.id = id;
this.salary = salary;
}
public double CalculateSalary()
{
//implementation
}
public void Save(FileStream fs)
{
//implementation
}
public void Load(FileStream fs)
{
//implementation
}
}
・「OCP」に関するサンプル
改善前
enum AccountType
{
SAVINGS,
FIXEDDEPOSIT,
SALARY
}
class AccountInfo
{
public string Name { get; set; }
public string Address { get; set; }
public int AccountNo { get; set; }
}
class Account
{
private AccountInfo info;
private AccountType type;
private double balance;
public Account(double balance, AccountType type)
{
this.balance = balance;
this.type = type;
}
public void Withdraw(double amount)
{
this.balance -= amount;
}
public void Deposit(double amount)
{
this.balance += amount;
}
public void CalculateInterest()
{
switch (this.type)
{
case AccountType.SAVINGS:
//implementation
break;
case AccountType.FIXEDDEPOSIT:
//implementation
break;
case AccountType.SALARY:
//implementation
break;
default:
break;
}//switch
}
}
改善前
class Switcher {
private $fan;
function __construct() {
$this->fan = new Fan();
}
function turnOn() {
$this->fan->on();
}
function turnOff() {
$this->fan->off();
}
}
・「LSP」に関するサンプル
改善前
abstract class Widget
{
public abstract void SetText();
public abstract string GetText();
}
class Button : Widget
{
public override void SetText()
{
//implementation
}
public override string GetText()
{
//implementation
}
}
class ListBox : Widget
{
public override void SetText()
{
//implementation
}
public override string GetText()
{
//implementation
}
public string[] GetTextArray()
{
//implementation
}
}
class Dialog
{
public void GetCaption(Widget widget)
{
string str = widget.GetText();
ListBox listbox = widget as ListBox;
if (listbox != null)
{
string[] selectItems = listbox.GetTextArray();
//implementation
}
else
{
//implementation
}
}
}
・「ISP」に関するサンプル
改善前
interface IFile
{
void Open();
void Close();
void Read();
void Write();
void Seek();
void Position();
}
class TextFile : IFile
{
#region IFile Members
public void Open()
{
//implementation
}
public void Close()
{
//implementation
}
public void Read()
{
//implementation
}
public void Write()
{
//implementation
}
public void Seek()
{
//implementation
}
public void Position()
{
//implementation
}
#endregion
}
class SocketFile : IFile
{
#region IFile Members
public void Open()
{
//implementation
}
public void Close()
{
//implementation
}
public void Read()
{
//implementation
}
public void Write()
{
//implementation
}
public void Seek()
{
throw new NotImplementedException();
}
public void Position()
{
throw new NotImplementedException();
}
#endregion
}
改善前
interface Broker {
function buy($symbol, $volume);
function sell($symbol, $volume);
function dailyLosses($date);
function dailyEarnings($date);
}
class TOPIXBroker implements Broker {
public function buy($symbol, $volume) {
...
}
public function sell($symbol, $volume) {
...
}
public function dailyLosses($date) {
...
}
public function dailyEarnings($date) {
...
}
}
class StockMarket {
private $broker;
function __construct(Broker $broker) {
$this->broker = $broker;
}
function buyStocks() {
$this->broker->buy($data['sybmol'], $data['volume']);
}
function sellStocks() {
$this->broker->sell($data['sybmol'], $data['volume']);
}
}
class DailyReporter {
private $broker;
function __construct(Broker $broker) {
$this->broker = $broker;
}
function currentBalance() {
echo 'Today: ' . date(time()) . "\n";
echo 'Earnings: ' . $this->broker->dailyEarnings(time()) . "\n";
echo 'Losses: ' . $this->broker->dailyLosses(time()) . "\n";
}
}
・「DIP」に関するサンプル
改善前
class Lamp
{
public void TurnOn()
{
//implementation
}
public void TurnOff()
{
//implementation
}
}
class Button
{
private Lamp lamp = new Lamp();
private bool pressed = false;
public void Press()
{
if (this.pressed)
{
this.lamp.TurnOff();
}
else
{
this.lamp.TurnOn();
this.pressed = true;
}//if
}
}
改善後
class Employee
{
private string name;
private int id;
private double salary;
public Employee(string name, int id, double salary)
{
this.name = name;
this.id = id;
this.salary = salary;
}
public double CalculateSalary()
{
//implementation
}
}
class Db
{
public void Save(Employee emp)
{
//implementation
}
public void Load(Employee emp)
{
//implementation
}
}
改善後
class AccountInfo
{
public string Name { get; set; }
public string Address { get; set; }
public int AccountNo { get; set; }
}
abstract class Account
{
protected AccountInfo info;
protected double balance;
public Account(double balance)
{
this.balance = balance;
}
public void Withdraw(double amount)
{
this.balance -= amount;
}
public void Deposit(double amount)
{
this.balance += amount;
}
public abstract void CalculateInterest();
}
class Savings : Account
{
public Savings(double balance) : base(balance) { }
public override void CalculateInterest()
{
//implementation
}
}
class FixedDeposit : Account
{
public FixedDeposit(double balance) : base(balance) { }
public override void CalculateInterest()
{
//implementation
}
}
class Salary : Account
{
public Salary(double balance) : base(balance) { }
public override void CalculateInterest()
{
//implementation
}
}
改善後
interface Switchable {
function on();
function off();
}
class Fan implements Switchable {
public function on() {
...
}
public function off() {
...
}
}
class Switcher {
private $switchable;
function __construct(Switchable $switchable) {
$this->switchable = $switchable;
}
function turnOn() {
$this->switchable->on();
}
function turnOff() {
$this->switchable->off();
}
}
$fan = new Fan();
$switch = new Switcher($fan);
$switch->turnOn();
$switch->turnOff();
改善後
abstract class Widget
{
public abstract void SetText();
public abstract string GetText();
}
class Button : Widget
{
public override void SetText()
{
//implementation
}
public override string GetText()
{
//implementation
}
}
class ListBox : Widget
{
public override void SetText()
{
//implementation
}
public override string GetText()
{
//implementation
}
public string[] GetTextArray()
{
//implementation
}
}
class Dialog
{
public void GetCaption(Widget widget)
{
string str = widget.GetText();
//implementation
}
}
class ListBoxDialog : Dialog
{
public void GetCaption(ListBox listbox)
{
base.GetCaption(listbox);
string[] selectItems = listbox.GetTextArray();
//implementation
}
}
改善後
interface IFile
{
void Open();
void Close();
void Read();
void Write();
}
interface IDiskFile : IFile
{
void Seek();
void Position();
}
class TextFile : IDiskFile
{
#region IFile Members
public void Open()
{
//implementation
}
public void Close()
{
//implementation
}
public void Read()
{
//implementation
}
public void Write()
{
//implementation
}
public void Seek()
{
//implementation
}
public void Position()
{
//implementation
}
#endregion
}
class SocketFile : IFile
{
#region IFile Members
public void Open()
{
//implementation
}
public void Close()
{
//implementation
}
public void Read()
{
//implementation
}
public void Write()
{
//implementation
}
#endregion
}
改善後
interface BrokerTransactions {
function buy($symbol, $volume);
function sell($symbol, $volume);
}
interface BrokerStatistics {
function dailyLosses($date);
function dailyEarnings($date);
}
class TOPIXBroker implements BrokerTransactions, BrokerStatistics {
public function buy($symbol, $volume) {
...
}
public function sell($symbol, $volume) {
...
}
public function dailyLosses($date) {
...
}
public function dailyEarnings($date) {
...
}
}
class StockMarket {
private $broker;
function __construct(BrokerTransactions $broker) {
$this->broker = $broker;
}
function buyStocks() {
$this->broker->buy($data['sybmol'], $data['volume']);
}
function sellStocks() {
$this->broker->sell($data['sybmol'], $data['volume']);
}
}
class DailyReporter {
private $broker;
function __construct(BrokerStatistics $broker) {
$this->broker = $broker;
}
function currentBalance() {
echo 'Today: ' . date(time()) . "\n";
echo 'Earnings: ' . $this->broker->dailyEarnings(time()) . "\n";
echo 'Losses: ' . $this->broker->dailyLosses(time()) . "\n";
}
}
改善後
interface ISwitch
{
void TurnOn();
void TurnOff();
}
class Lamp : ISwitch
{
#region ISwitch Members
public void TurnOn()
{
//implementation
}
public void TurnOff()
{
//implementation
}
#endregion
}
class Button
{
private ISwitch iSwitch;
private bool pressed = false;
public void SetSwitch(ISwitch s)
{
this.iSwitch = s;
}
public void Press()
{
if (this.pressed)
{
this.iSwitch.TurnOff();
}
else
{
this.iSwitch.TurnOn();
this.pressed = true;
}//if
}
}