设计模式六大原则
开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象.
依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
迪米特法则 :一个对象应该对其他对象保持最少的了解。
单例模式 (创建设计模式)
要点:只有一个实例,作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
常见: 数据库连接,日志错误记录(多种用途使用多种模式)
<?php
/**
* 单例模式
*/
class Singleton
{
/**
* @var self[保存实例]
*/
private static $instance;
/**
* @var
*/
public $mix;
/**
* return self instance [创建一个用来实例化对象的方法]
*/
public static function getInstace()
{
var_dump(isset(self::$instance));
if (!self::$instance instanceof self) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Singleton constructor.构造函数为private,防止创建对象
*/
private function __construct()
{
echo "实例初始化了";
}
private function __clone()
{
// TODO: Implement __clone() method.
trigger_error('Clone is not allowed!');
}
}
// @Test
$firstSingle = Singleton::getInstace();
$secondSingle = Singleton::getInstace();
$firstSingle->mix = 'one';
//一开始mix是赋值‘one',所以打印出one
print_r($firstSingle->mix);
//由于getInstace该方法保证了Singleton类只能有一个实例,不会再重新new,minx依然用firstSingle的,mix被改变成’two‘
$secondSingle->mix = 'two';
print_r($firstSingle->mix);
print_r($secondSingle->mix);
打印结果:bool(false) 实例初始化了bool(true) onetwotwo
简单工厂模式 (创建设计模式)
要点:可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
<?php
/**
* 简单工厂模式
*/
interface SystemFactory
{
public function createSystem($type);
}
class MySystemFactory implements SystemFactory
{
// 实现工厂方法
public function createSystem($type)
{
switch ($type) {
case 'Mac':
return new MacSystem();
case 'Win':
return new WinSystem();
case 'Linux':
return new LinuxSystem();
}
}
}
class MacSystem
{
public function __construct()
{
echo "I am Mac system</br>";
}
}
class WinSystem
{
public function __construct()
{
echo "I am Win system</br>";
}
}
class LinuxSystem
{
public function __construct()
{
echo "I am Linux system</br>";
}
}
//创建系统工厂
$systemObj = new MySystemFactory();
$systemArray = array('Mac','Linux','Win');
foreach ($systemArray as $val) {
$systemObj->createSystem($val);
}
打印结果:
I am Mac system
I am Linux system
I am Win system
工厂模式 (创建设计模式)
要点:此模式中,通过定义一个抽象的核心工厂类,并定义创建产品对象的接口,创建具体产品实例的工作延迟到其工厂子类去完成。这样做的好处是核心类只关注工厂类的接口定义,而具体的产品实例交给具体的工厂子类去创建。当系统需要新增一个产品,无需修改现有系统代码,只需要添加一个具体产品类和其对应的工厂子类,是系统的扩展性变得很好,符合面向对象编程的开闭原则;
我的理解:
按我平时喜欢玩的篮球游戏nba2k系列来代入。我来模拟整个NBA联盟,一开始是没有球员的,我需要不断的创建球员,具体就交给Nba底下的各个子类,也就是各个球队去创建就好
首先有一个球员接口,可以定义球员的投射还有抢篮板球的动作,注意这里的每个球员暂时只有这两个动作,生产出来的球员只有投射和抢篮板动作
interface Player{
public function shot();
public function rebound();
}
然后具体到球员自己的动作
class Wade implements Player
{
public function shot()
{
echo "I can shot in middle distance<br>";
}
public function rebound()
{
echo "I can crash the boards <br>";
}
}
class Kobe implements Player
{
public function shot()
{
echo "I can shot the three-point <br>";
}
public function rebound()
{
echo "I can crash the boards <br>";
}
}
定义一个抽象的核心工厂类,也就是整个游戏有一个创建球员页面
abstract class NbaFactory{
abstract static function createPlayer();
}
我喜欢热火,就来操作热火还有湖人好了,创一个韦德还有科比来玩玩
class HeatTeam extends NbaFactory{
public static function createPlayer()
{
return new Wade();
}
}
class LakersTeam extends NbaFactory{
public static function createPlayer()
{
return new Kobe();
}
}
一切准备好了,就去场上试试能不能打:选人然后投篮抢篮板
$heatPlayer = HeatTeam::createPlayer();
$heatPlayer->shot();
$heatPlayer->rebound();
$lakersPlayer = LakersTeam::createPlayer();
$lakersPlayer->shot();
$lakersPlayer->rebound();
所以工厂模式:不需要NBA这个背后大boss亲自去创建球员,只需要定义一个想要创建球员这样的接口,实例工作就交给子类也就是球队去创建就行了,当我们想要增加一个自己喜欢的球员来玩,只需要添加一个具体的球员,然后设置他有什么动作呀,能力呀,再对应你想要他在哪一支队伍就ok了,这样就不需要修改现有系统代码,系统的扩展性变得很好,符合面向对象编程的开闭原则
整体代码如下:
<?php
/**
* 球员动作
* Interface Player
*/
interface Player{
public function shot();
public function rebound();
}
/**
* 设置韦德投篮以及抢篮板
* Class Wade
*/
class Wade implements Player
{
public function shot()
{
echo "I can shot in middle distance<br>";
}
public function rebound()
{
echo "I can crash the boards <br>";
}
}
/**
* 设置科比投篮以及抢篮板
* Class Kobe
*/
class Kobe implements Player
{
public function shot()
{
echo "I can shot the three-point <br>";
}
public function rebound()
{
echo "I can crash the boards <br>";
}
}
/**
* 整个游戏NBA具备创建球员这一项功能
* Class NbaFactory
*/
abstract class NbaFactory{
abstract static function createPlayer();
}
/**
* 热火队创建了韦德这样的球员
* Class HeatTeam
*/
class HeatTeam extends NbaFactory{
public static function createPlayer()
{
return new Wade();
}
}
/**
* 湖人队创建了科比这样的球员
* Class LakersTeam
*/
class LakersTeam extends NbaFactory{
public static function createPlayer()
{
return new Kobe();
}
}
/**
* 选择热火队,并且测试韦德的动作
*/
$heatPlayer = HeatTeam::createPlayer();
$heatPlayer->shot();
$heatPlayer->rebound();
/**
* 选择湖人队,并且测试科比的动作
*/
$lakersPlayer = LakersTeam::createPlayer();
$lakersPlayer->shot();
$lakersPlayer->rebound();
抽象工厂模式 (创建设计模式)
要点:提供一个创建一系列相关或相互依赖对象的接口。注意:这里和工厂方法的区别是:一系列(多个),而工厂方法只有一个。。在工厂方法模式中,一个具体的工厂负责生产一类具体的产品,即一对一的关系,但是,如果需要一个具体的工厂生产多种产品对象,那么就需要用到抽象工厂模式了。
我的理解:
工厂模式,一个工厂辅助生产一类具体的产品,就像上边的例子,球员创建,只有投篮还有抢篮板动作,无论创建韦德科比还是詹姆斯都是只有这两种。而抽象工厂,需要生产多种产品,例如下面有两个游戏页面,球衣样式设置和球鞋样式设置,这两个页面底下是各种包含自己的方法,球衣页面是主客场球衣设置,球鞋页面是高低帮和颜色设置。
整体代码如下:
<?php
/**
* 球衣样式设置(客场球衣&主场球衣)
* Interface Uniform
*/
interface Uniform{
public function home();
public function away();
}
/**
* 设置热火主客场球衣样式
* Class HeatUniform
*/
class HeatUniform implements Uniform
{
public function home()
{
echo "Set the Heat's uniform with red and white <br>";
}
public function away()
{
echo "Set the Heat's uniform with black and red <br><br>";
}
}
/**
* 球鞋样式设置(球鞋款式&球鞋主颜色)
* Interface Shoes
*/
interface Shoes{
public function style();
public function color();
}
/**
* 设置热火主客场球衣样式
* Class HeatUniform
*/
class HeatShoes implements Shoes
{
public function style()
{
echo "Set the Heat's Shoes'style as height shoes <br>";
}
public function color()
{
echo "Set the Heat's Shoes'color as white <br>";
}
}
/**
* 游戏球队设置页面,包括了服装设置和球鞋设置
* Class TeamSetting
*/
abstract class TeamSetting{
abstract public static function setUniform();
abstract public static function setShoes();
}
/**
* 热火队的球队设置页面,有热火球衣和热火球鞋设置
* Class HeatSetting
*/
class HeatSetting extends TeamSetting
{
public static function setUniform()
{
return new HeatUniform();
}
public static function setShoes()
{
return new HeatShoes();
}
}
/**
* 操作一:进入热火队球衣设置,主场球衣设置为红白,客场球衣设置为红黑
*/
$myControl1 = HeatSetting::setUniform();
$myControl1->home();
$myControl1->away();
/**
* 操作二:进入热火队球鞋设置,球鞋样式设置为高帮,颜色设置为白色
*/
$myControl2 = HeatSetting::setShoes();
$myControl2->style();
$myControl2->color();