玩转简单工厂设计模式

最近在看《headfirst 设计模式》,发现简单工厂,工厂模式,抽象工厂模式这三者的区别于联系不是太好理解,经过研究之后,写几个例子,加深一下印象。

首先是简单工厂

package go.derek;
//虽然是简单工厂,但也要定义一个接口,从而可以达到运行时多态的效果
//这是一个小汽车的接口
public interface Car{
	//car的基本信息
	public void intro();
}
//定义 宝马745Li 类,实现Car接口
class Bmw_745Li implements Car{
	private String brand="宝马";
	private String type="745Li";
	public void intro(){
		System.out.println("这是一辆"+brand+"车,型号是"+type+"");
	}
}
//定义 奥迪A8L 类,实现Car接口
class Audi_A8L implements Car{
	private String brand="奥迪";
	private String type="A8L";
	public void intro(){
		System.out.println("这是一辆"+brand+"车,型号是"+type+"");
	}
}
//工厂类,用来封装实例的创建
class CarFactory{
	public static Car create(String brand,String type){
		Car car=null;
		if(brand.equals("宝马")){
			if(type.equals("745Li")){
				car= new Bmw_745Li();
			}
		}
		else if(brand.equals("奥迪")){
			if(type.equals("A8L")){
				car=new Audi_A8L();
			}
		}
		else{
			car=null;
		}
		return car;
	}
}
package go.derek;
//测试类
public class FactoryTest{
	public static void main(String[] args){
		Car car1=CarFactory.create("宝马", "745Li");
		car1.intro();
		Car car2=CarFactory.create("奥迪", "A8L");
		car2.intro();
	}
}
运行结果如下

这是一辆宝马车,型号是745Li
这是一辆奥迪车,型号是A8L

在测试类里面可以看到运行时多态的效果,调用intro方法的不是具体的宝马或奥迪,而是car接口的引用。

在测试类里面也看不到new关键字,对象的创建被成功封装在了create这个工厂方法里面。

在实际应用中,这个测试类其实就相当于一个客户端的调用,所以这个工厂方法就成功将具体的car实现类与客户端类解耦了。

但简单工厂模式的局限也很明显。当car的实现类大量增加的时候,工厂方法里面的依赖变得臃肿起来,宝马不仅有745型号,还有735,755,523,525,320,323,325等等。。

同样奥迪也是一样,此外汽车品牌也绝对不只有这两个。。奔驰,法拉利,宾利,路虎,数不胜数。。所以简单工厂模式适用于实现类不是太多,扩展可能性不太大的情形。


<think>好的,用户现在想详细了解如何使用C#设计模式结合窗体应用程序实现五子棋游戏的开发过程,特别是使用WinForms或WPF的完整步骤和代码示例。首先,我需要回顾之前的对话,确保新回答与之前的建议一致,并解决用户的新需求。 用户之前的提问是关于设计模式在五子棋中的应用,我给出了工厂模式、状态模式、观察者模式等的示例,现在用户希望更详细的开发步骤和代码。需要结合WinForms或WFF的具体实现,可能用户更倾向于实际操作指导。 首先,用户提到了引用中的MvvmCross框架,但根据用户当前的问题,他们可能需要的是直接使用WinForms或WPF的示例,而不是跨平台框架。因此,在回答时可能需要明确说明选择WinForms还是WPF,并给出相应的代码结构。考虑到用户要求详细步骤,可能更适合使用WinForms,因为它的上手相对简单,适合分步讲解。 接下来,用户需要结合设计模式,所以需要回顾之前的模式应用,如工厂模式创建玩家、状态模式管理游戏状态、观察者模式处理棋盘更新。在详细步骤中,需要将这些模式自然地融入各个模块的开发中,并给出代码示例。 另外,用户可能需要了解如何将界面与逻辑分离,尤其是在WPF中使用MVVM模式。但用户的问题中提到的是窗体应用程序,可能更偏向WinForms,但也可以简要对比WPF的实现方式,例如在游戏控制器中使用事件或绑定机制。 需要确保代码示例的正确性,比如棋盘绘制的网格计算、鼠标点击事件处理、胜负判断算法等关键部分。胜负判断需要检查四个方向是否有连续五个棋子,这部分需要详细的逻辑说明和代码实现。 此外,用户可能需要了解如何实现AI对手,这里可以提到使用策略模式来切换不同难度的AI,但根据当前问题的重点,可能放在基础实现上,AI部分可以简要提及或作为扩展内容。 最后,要生成相关问题,引导用户深入探讨设计模式的其他应用或具体实现细节,如状态模式的具体转换、观察者模式的通知机制等。 总结步骤: 1. 确定使用WinForms作为开发框架,分步讲解界面和逻辑。 2. 应用工厂模式创建玩家实例,区分人类和AI玩家。 3. 使用状态模式管理游戏的不同状态(进行中、结束)。 4. 观察者模式或事件机制处理棋盘更新和界面重绘。 5. 实现棋盘绘制、落子逻辑、胜负判断。 6. 提供完整的代码示例,并解释关键部分。 7. 对比WPF的MVVM实现,说明差异和优势。 8. 生成相关问题,引导进一步学习。 需要确保回答结构清晰,代码注释明确,设计模式的应用点突出,同时覆盖用户需求中的所有方面。</think>以下是用C#设计模式结合WinForms实现五子棋游戏的详细开发指南,包含关键设计模式应用和完整代码实现: ### 一、项目结构规划 ``` GobangGame ├── Models // 数据模型 ├── Views // 窗体界面 ├── Controllers // 游戏控制 ├── Patterns // 设计模式实现 └── Utilities // 工具类 ``` ### 二、核心模式实现 #### 1. 工厂模式 - 玩家对象创建 ```csharp // Patterns/PlayerFactory.cs public interface IPlayer { void MakeMove(Point position); } public class HumanPlayer : IPlayer { public void MakeMove(Point position) { BoardManager.Instance.PlaceStone(position.X, position.Y); } } public class PlayerFactory { public IPlayer CreatePlayer(string type) { return type switch { "Human" => new HumanPlayer(), "AI" => new AIPlayer(), _ => throw new ArgumentException("无效的玩家类型") }; } } ``` #### 2. 状态模式 - 游戏流程控制 ```csharp // Patterns/GameState.cs public interface IGameState { void HandleClick(Point position); } public class PlayingState : IGameState { public void HandleClick(Point pos) { var board = BoardManager.Instance; if (board.IsValidPosition(pos)) { board.PlaceStone(pos.X, pos.Y); WinChecker.CheckWinner(pos); } } } public class GameOverState : IGameState { public void HandleClick(Point pos) { if (MessageBox.Show("再玩一局?", "游戏结束", MessageBoxButtons.YesNo) == DialogResult.Yes) { GameController.Instance.ResetGame(); } } } ``` ### 三、窗体实现(WinForms) #### 1. 主窗体代码 ```csharp // Views/MainForm.cs public partial class MainForm : Form { private const int GRID_SIZE = 40; private readonly BoardManager _board = BoardManager.Instance; public MainForm() { InitializeComponent(); this.Paint += DrawBoard; this.MouseClick += HandleBoardClick; } private void DrawBoard(object sender, PaintEventArgs e) { using var g = e.Graphics; // 绘制棋盘网格 for (int i = 0; i < 15; i++) { g.DrawLine(Pens.Black, i*GRID_SIZE, 0, i*GRID_SIZE, 14*GRID_SIZE); g.DrawLine(Pens.Black, 0, i*GRID_SIZE, 14*GRID_SIZE, i*GRID_SIZE); } // 绘制棋子 for (int x = 0; x < 15; x++) { for (int y = 0; y < 15; y++) { if (_board[x, y] != 0) { var brush = _board[x, y] == 1 ? Brushes.Black : Brushes.White; g.FillEllipse(brush, x*GRID_SIZE-15, y*GRID_SIZE-15, 30, 30); } } } } private void HandleBoardClick(object sender, MouseEventArgs e) { var pos = new Point(e.X / GRID_SIZE, e.Y / GRID_SIZE); GameController.Instance.CurrentState.HandleClick(pos); this.Invalidate(); // 触发重绘 } } ``` ### 四、游戏控制核心 #### 1. 单例棋盘管理 ```csharp // Controllers/BoardManager.cs public class BoardManager { private static readonly Lazy<BoardManager> _instance = new(() => new BoardManager()); private int[,] _board = new int[15, 15]; public static BoardManager Instance => _instance.Value; public bool PlaceStone(int x, int y) { if (_board[x, y] != 0) return false; _board[x, y] = CurrentPlayer; CurrentPlayer = 3 - CurrentPlayer; // 切换玩家 return true; } } ``` #### 2. 胜负判定算法 ```csharp // Utilities/WinChecker.cs public static class WinChecker { public static bool CheckWinner(Point lastMove) { int player = BoardManager.Instance[lastMove.X, lastMove.Y]; return CheckDirection(lastMove, 1, 0, player) || // 水平 CheckDirection(lastMove, 0, 1, player) || // 垂直 CheckDirection(lastMove, 1, 1, player) || // 主对角线 CheckDirection(lastMove, 1, -1, player); // 副对角线 } private static bool CheckDirection(Point pos, int dx, int dy, int player) { int count = 1; // 正向检测 for (int i = 1; i < 5; i++) { int x = pos.X + dx*i; int y = pos.Y + dy*i; if (!IsSameColor(x, y, player)) break; count++; } // 反向检测 for (int i = 1; i < 5; i++) { int x = pos.X - dx*i; int y = pos.Y - dy*i; if (!IsSameColor(x, y, player)) break; count++; } return count >= 5; } } ``` ### 五、WPF实现差异(MVVM模式) ```csharp // ViewModels/GameViewModel.cs public class GameViewModel : INotifyPropertyChanged { private ObservableCollection<int> _cells = new(Enumerable.Repeat(0, 225)); public ICommand CellClickCommand { get; } public GameViewModel() { CellClickCommand = new RelayCommand<int>(index => { int x = index % 15; int y = index / 15; GameController.Instance.HandleInput(new Point(x, y)); }); } // 数据绑定更新 public int this[int index] { get => _cells[index]; set { _cells[index] = value; OnPropertyChanged($"Item[{index}]"); } } } ``` ### 六、开发步骤 1. **创建WinForms项目**:添加15x15棋盘绘制逻辑 2. **实现棋盘管理类**:使用单例模式确保全局访问 3. **设计玩家工厂**:支持人类/AI玩家切换 4. **绑定鼠标事件**:将物理坐标转换为棋盘坐标 5. **实现状态模式**:区分游戏进行与结束状态 6. **添加胜负判定**:四方向连续检测算法 7. **实现AI模块**:采用策略模式实现智能落子
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值